1/* 2 * Copyright (c) 1982, 1986, 1988, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 17 unchanged lines hidden (view full) --- 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 |
34 * $FreeBSD: head/sys/netinet/ip_output.c 55009 1999-12-22 19:13:38Z shin $ |
35 */ 36 37#define _IP_VHL 38 39#include "opt_ipfw.h" 40#include "opt_ipdn.h" 41#include "opt_ipdivert.h" 42#include "opt_ipfilter.h" |
43#include "opt_ipsec.h" |
44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/malloc.h> 49#include <sys/mbuf.h> 50#include <sys/protosw.h> 51#include <sys/socket.h> 52#include <sys/socketvar.h> |
53#include <sys/proc.h> |
54 55#include <net/if.h> 56#include <net/route.h> 57 58#include <netinet/in.h> 59#include <netinet/in_systm.h> 60#include <netinet/ip.h> 61#include <netinet/in_pcb.h> 62#include <netinet/in_var.h> 63#include <netinet/ip_var.h> 64 |
65#include "faith.h" 66 |
67#ifdef vax 68#include <machine/mtpr.h> 69#endif 70#include <machine/in_cksum.h> 71 72static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); 73 |
74#ifdef IPSEC 75#include <netinet6/ipsec.h> 76#include <netkey/key.h> 77#ifdef IPSEC_DEBUG 78#include <netkey/key_debug.h> 79#else 80#define KEYDEBUG(lev,arg) 81#endif 82#endif /*IPSEC*/ 83 |
84#include <netinet/ip_fw.h> 85 86#ifdef DUMMYNET 87#include <netinet/ip_dummynet.h> 88#endif 89 90#ifdef IPFIREWALL_FORWARD_DEBUG 91#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ --- 40 unchanged lines hidden (view full) --- 132 struct ip *ip, *mhip; 133 struct ifnet *ifp; 134 struct mbuf *m = m0; 135 int hlen = sizeof (struct ip); 136 int len, off, error = 0; 137 struct sockaddr_in *dst; 138 struct in_ifaddr *ia; 139 int isbroadcast; |
140#ifdef IPSEC 141 struct route iproute; 142 struct socket *so; 143 struct secpolicy *sp = NULL; 144#endif |
145 u_int16_t divert_cookie; /* firewall cookie */ 146#ifdef IPFIREWALL_FORWARD 147 int fwd_rewrite_src = 0; 148#endif 149 struct ip_fw_chain *rule = NULL; 150 151#ifdef IPDIVERT 152 /* Get and reset firewall cookie */ 153 divert_cookie = ip_divert_cookie; 154 ip_divert_cookie = 0; 155#else 156 divert_cookie = 0; 157#endif |
158 159#ifdef IPSEC 160 /* 161 * NOTE: If IP_SOCKINMRCVIF flag is set, 'socket *' is kept in 162 * m->m_pkthdr.rcvif for later IPSEC check. In this case, 163 * m->m_pkthdr will be NULL cleared after the contents is saved in 164 * 'so'. 165 * NULL clearance of rcvif should be natural because the packet should 166 * have been sent from my own socket and has no rcvif in this case. 167 * It is also necessary because someone might consider it as 168 * 'ifnet *', and cause SEGV. 169 */ 170 if ((flags & IP_SOCKINMRCVIF) != 0) { 171#if defined(IPFIREWALL) && defined(DUMMYNET) 172 if (m->m_type == MT_DUMMYNET) { 173 so = (struct socket *)m->m_next->m_pkthdr.rcvif; 174 m->m_next->m_pkthdr.rcvif = NULL; 175 } else 176#endif 177 { 178 so = (struct socket *)m->m_pkthdr.rcvif; 179 m->m_pkthdr.rcvif = NULL; 180 } 181 } else 182 so = NULL; 183#endif /*IPSEC*/ |
184 185#if defined(IPFIREWALL) && defined(DUMMYNET) 186 /* 187 * dummynet packet are prepended a vestigial mbuf with 188 * m_type = MT_DUMMYNET and m_data pointing to the matching 189 * rule. 190 */ 191 if (m->m_type == MT_DUMMYNET) { 192 /* 193 * the packet was already tagged, so part of the 194 * processing was already done, and we need to go down. 195 * opt, flags and imo have already been used, and now 196 * they are used to hold ifp, dst and NULL, respectively. 197 */ 198 rule = (struct ip_fw_chain *)(m->m_data) ; |
199 dst = (struct sockaddr_in *)((struct dn_pkt *)m)->dn_dst; |
200 m0 = m = m->m_next ; 201 ip = mtod(m, struct ip *); |
202 ifp = (struct ifnet *)opt; 203 hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; 204 opt = NULL ; |
205 goto sendit; 206 } else 207 rule = NULL ; 208#endif 209 210#ifdef DIAGNOSTIC 211 if ((m->m_flags & M_PKTHDR) == 0) 212 panic("ip_output no HDR"); --- 281 unchanged lines hidden (view full) --- 494 * pass the pkt to dummynet. Need to include 495 * pipe number, m, ifp, ro, dst because these are 496 * not recomputed in the next pass. 497 * All other parameters have been already used and 498 * so they are not needed anymore. 499 * XXX note: if the ifp or ro entry are deleted 500 * while a pkt is in dummynet, we are in trouble! 501 */ |
502 dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,dst,rule, 503 flags); |
504 goto done; 505 } 506#endif 507#ifdef IPDIVERT 508 if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) { 509 struct mbuf *clone = NULL; 510 511 /* Clone packet if we're doing a 'tee' */ --- 125 unchanged lines hidden (view full) --- 637 * we have to drop the pkt 638 */ 639 m_freem(m); 640 error = EACCES; /* not sure this is the right error msg */ 641 goto done; 642 } 643 644pass: |
645#ifdef IPSEC 646 /* get SP for this packet */ 647 if (so == NULL) 648 sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); 649 else 650 sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); 651 652 if (sp == NULL) { 653 ipsecstat.out_inval++; 654 goto bad; 655 } 656 657 error = 0; 658 659 /* check policy */ 660 switch (sp->policy) { 661 case IPSEC_POLICY_DISCARD: 662 /* 663 * This packet is just discarded. 664 */ 665 ipsecstat.out_polvio++; 666 goto bad; 667 668 case IPSEC_POLICY_BYPASS: 669 case IPSEC_POLICY_NONE: 670 /* no need to do IPsec. */ 671 goto skip_ipsec; 672 673 case IPSEC_POLICY_IPSEC: 674 if (sp->req == NULL) { 675 /* XXX should be panic ? */ 676 printf("ip_output: No IPsec request specified.\n"); 677 error = EINVAL; 678 goto bad; 679 } 680 break; 681 682 case IPSEC_POLICY_ENTRUST: 683 default: 684 printf("ip_output: Invalid policy found. %d\n", sp->policy); 685 } 686 687 ip->ip_len = htons((u_short)ip->ip_len); 688 ip->ip_off = htons((u_short)ip->ip_off); 689 ip->ip_sum = 0; 690 691 { 692 struct ipsec_output_state state; 693 bzero(&state, sizeof(state)); 694 state.m = m; 695 if (flags & IP_ROUTETOIF) { 696 state.ro = &iproute; 697 bzero(&iproute, sizeof(iproute)); 698 } else 699 state.ro = ro; 700 state.dst = (struct sockaddr *)dst; 701 702 error = ipsec4_output(&state, sp, flags); 703 704 m = state.m; 705 if (flags & IP_ROUTETOIF) { 706 /* 707 * if we have tunnel mode SA, we may need to ignore 708 * IP_ROUTETOIF. 709 */ 710 if (state.ro != &iproute || state.ro->ro_rt != NULL) { 711 flags &= ~IP_ROUTETOIF; 712 ro = state.ro; 713 } 714 } else 715 ro = state.ro; 716 dst = (struct sockaddr_in *)state.dst; 717 if (error) { 718 /* mbuf is already reclaimed in ipsec4_output. */ 719 m0 = NULL; 720 switch (error) { 721 case EHOSTUNREACH: 722 case ENETUNREACH: 723 case EMSGSIZE: 724 case ENOBUFS: 725 case ENOMEM: 726 break; 727 default: 728 printf("ip4_output (ipsec): error code %d\n", error); 729 /*fall through*/ 730 case ENOENT: 731 /* don't show these error codes to the user */ 732 error = 0; 733 break; 734 } 735 goto bad; 736 } 737 } 738 739 /* be sure to update variables that are affected by ipsec4_output() */ 740 ip = mtod(m, struct ip *); 741#ifdef _IP_VHL 742 hlen = IP_VHL_HL(ip->ip_vhl) << 2; 743#else 744 hlen = ip->ip_hl << 2; 745#endif 746 if (ro->ro_rt == NULL) { 747 if ((flags & IP_ROUTETOIF) == 0) { 748 printf("ip_output: " 749 "can't update route after IPsec processing\n"); 750 error = EHOSTUNREACH; /*XXX*/ 751 goto bad; 752 } 753 } else { 754 /* nobody uses ia beyond here */ 755 ifp = ro->ro_rt->rt_ifp; 756 } 757 758 /* make it flipped, again. */ 759 ip->ip_len = ntohs((u_short)ip->ip_len); 760 ip->ip_off = ntohs((u_short)ip->ip_off); 761skip_ipsec: 762#endif /*IPSEC*/ 763 |
764 /* 765 * If small enough for interface, can just send directly. 766 */ 767 if ((u_short)ip->ip_len <= ifp->if_mtu) { 768 ip->ip_len = htons((u_short)ip->ip_len); 769 ip->ip_off = htons((u_short)ip->ip_off); 770 ip->ip_sum = 0; 771 if (ip->ip_vhl == IP_VHL_BORING) { --- 111 unchanged lines hidden (view full) --- 883 else 884 m_freem(m); 885 } 886 887 if (error == 0) 888 ipstat.ips_fragmented++; 889 } 890done: |
891#ifdef IPSEC 892 if (ro == &iproute && ro->ro_rt) { 893 RTFREE(ro->ro_rt); 894 ro->ro_rt = NULL; 895 } 896 if (sp != NULL) { 897 KEYDEBUG(KEYDEBUG_IPSEC_STAMP, 898 printf("DP ip_output call free SP:%p\n", sp)); 899 key_freesp(sp); 900 } 901#endif /* IPSEC */ |
902 return (error); 903bad: 904 m_freem(m0); 905 goto done; 906} 907 908/* 909 * Insert IP options into preformed packet. --- 128 unchanged lines hidden (view full) --- 1038 } 1039 1040 case IP_TOS: 1041 case IP_TTL: 1042 case IP_RECVOPTS: 1043 case IP_RECVRETOPTS: 1044 case IP_RECVDSTADDR: 1045 case IP_RECVIF: |
1046#if defined(NFAITH) && NFAITH > 0 1047 case IP_FAITH: 1048#endif |
1049 error = sooptcopyin(sopt, &optval, sizeof optval, 1050 sizeof optval); 1051 if (error) 1052 break; 1053 1054 switch (sopt->sopt_name) { 1055 case IP_TOS: 1056 inp->inp_ip_tos = optval; --- 18 unchanged lines hidden (view full) --- 1075 1076 case IP_RECVDSTADDR: 1077 OPTSET(INP_RECVDSTADDR); 1078 break; 1079 1080 case IP_RECVIF: 1081 OPTSET(INP_RECVIF); 1082 break; |
1083 1084#if defined(NFAITH) && NFAITH > 0 1085 case IP_FAITH: 1086 OPTSET(INP_FAITH); 1087 break; 1088#endif |
1089 } 1090 break; 1091#undef OPTSET 1092 1093 case IP_MULTICAST_IF: 1094 case IP_MULTICAST_VIF: 1095 case IP_MULTICAST_TTL: 1096 case IP_MULTICAST_LOOP: --- 25 unchanged lines hidden (view full) --- 1122 break; 1123 1124 default: 1125 error = EINVAL; 1126 break; 1127 } 1128 break; 1129 |
1130#ifdef IPSEC 1131 case IP_IPSEC_POLICY: 1132 { 1133 caddr_t req; 1134 int priv; 1135 struct mbuf *m; 1136 int optname; 1137 1138 if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */ 1139 break; 1140 if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */ 1141 break; 1142 priv = (sopt->sopt_p != NULL && 1143 suser(sopt->sopt_p) != 0) ? 0 : 1; 1144 req = mtod(m, caddr_t); 1145 optname = sopt->sopt_name; 1146 error = ipsec4_set_policy(inp, optname, req, priv); 1147 m_freem(m); 1148 break; 1149 } 1150#endif /*IPSEC*/ 1151 |
1152 default: 1153 error = ENOPROTOOPT; 1154 break; 1155 } 1156 break; 1157 1158 case SOPT_GET: 1159 switch (sopt->sopt_name) { --- 10 unchanged lines hidden (view full) --- 1170 1171 case IP_TOS: 1172 case IP_TTL: 1173 case IP_RECVOPTS: 1174 case IP_RECVRETOPTS: 1175 case IP_RECVDSTADDR: 1176 case IP_RECVIF: 1177 case IP_PORTRANGE: |
1178#if defined(NFAITH) && NFAITH > 0 1179 case IP_FAITH: 1180#endif |
1181 switch (sopt->sopt_name) { 1182 1183 case IP_TOS: 1184 optval = inp->inp_ip_tos; 1185 break; 1186 1187 case IP_TTL: 1188 optval = inp->inp_ip_ttl; --- 20 unchanged lines hidden (view full) --- 1209 case IP_PORTRANGE: 1210 if (inp->inp_flags & INP_HIGHPORT) 1211 optval = IP_PORTRANGE_HIGH; 1212 else if (inp->inp_flags & INP_LOWPORT) 1213 optval = IP_PORTRANGE_LOW; 1214 else 1215 optval = 0; 1216 break; |
1217 1218#if defined(NFAITH) && NFAITH > 0 1219 case IP_FAITH: 1220 optval = OPTBIT(INP_FAITH); 1221 break; 1222#endif |
1223 } 1224 error = sooptcopyout(sopt, &optval, sizeof optval); 1225 break; 1226 1227 case IP_MULTICAST_IF: 1228 case IP_MULTICAST_VIF: 1229 case IP_MULTICAST_TTL: 1230 case IP_MULTICAST_LOOP: 1231 case IP_ADD_MEMBERSHIP: 1232 case IP_DROP_MEMBERSHIP: 1233 error = ip_getmoptions(sopt, inp->inp_moptions); 1234 break; 1235 |
1236#ifdef IPSEC 1237 case IP_IPSEC_POLICY: 1238 { 1239 struct mbuf *m; 1240 caddr_t req = NULL; 1241 1242 if (m != 0) 1243 req = mtod(m, caddr_t); 1244 error = ipsec4_get_policy(sotoinpcb(so), req, &m); 1245 if (error == 0) 1246 error = soopt_mcopyout(sopt, m); /* XXX */ 1247 m_freem(m); 1248 break; 1249 } 1250#endif /*IPSEC*/ 1251 |
1252 default: 1253 error = ENOPROTOOPT; 1254 break; 1255 } 1256 break; 1257 } 1258 return (error); 1259} --- 543 unchanged lines hidden --- |