From ef39adf007d3a9125dc4a03ece5a586c1519e8b8 Mon Sep 17 00:00:00 2001 From: Andre Oppermann Date: Fri, 18 Nov 2005 20:12:40 +0000 Subject: [PATCH] Consolidate all IP Options handling functions into ip_options.[ch] and include ip_options.h into all files making use of IP Options functions. From ip_input.c rev 1.306: ip_dooptions(struct mbuf *m, int pass) save_rte(m, option, dst) ip_srcroute(m0) ip_stripoptions(m, mopt) From ip_output.c rev 1.249: ip_insertoptions(m, opt, phlen) ip_optcopy(ip, jp) ip_pcbopts(struct inpcb *inp, int optname, struct mbuf *m) No functional changes in this commit. Discussed with: rwatson Sponsored by: TCP/IP Optimization Fundraise 2005 --- sys/conf/files | 1 + sys/netinet/igmp.c | 1 + sys/netinet/ip_fastfwd.c | 1 + sys/netinet/ip_icmp.c | 1 + sys/netinet/ip_input.c | 453 +----------------------- sys/netinet/ip_mroute.c | 1 + sys/netinet/ip_options.c | 708 +++++++++++++++++++++++++++++++++++++ sys/netinet/ip_options.h | 74 ++++ sys/netinet/ip_output.c | 213 +---------- sys/netinet/ip_var.h | 18 +- sys/netinet/tcp_input.c | 1 + sys/netinet/tcp_output.c | 1 + sys/netinet/tcp_reass.c | 1 + sys/netinet/tcp_syncache.c | 1 + sys/netinet/udp_usrreq.c | 1 + 15 files changed, 795 insertions(+), 681 deletions(-) create mode 100644 sys/netinet/ip_options.c create mode 100644 sys/netinet/ip_options.h diff --git a/sys/conf/files b/sys/conf/files index d029f9fce692..0650ad921c2c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1678,6 +1678,7 @@ netinet/ip_fw_pfil.c optional ipfirewall netinet/ip_icmp.c optional inet netinet/ip_input.c optional inet netinet/ip_mroute.c optional mrouting +netinet/ip_options.c optional inet netinet/ip_output.c optional inet netinet/raw_ip.c optional inet netinet/tcp_debug.c optional tcpdebug diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c index ea93c2e028b9..d82727d8287c 100644 --- a/sys/netinet/igmp.c +++ b/sys/netinet/igmp.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c index 1f5f535d629c..43419f3c5fe2 100644 --- a/sys/netinet/ip_fastfwd.c +++ b/sys/netinet/ip_fastfwd.c @@ -100,6 +100,7 @@ #include #include #include +#include #include diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index dd7e1251cedd..0d3131ac4e1c 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f84b562f6e9d..75563f002c0c 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #ifdef DEV_CARP #include @@ -101,19 +102,6 @@ int ip_defttl = IPDEFTTL; SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, &ip_defttl, 0, "Maximum TTL on IP packets"); -static int ip_dosourceroute = 0; -SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, - &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); - -static int ip_acceptsourceroute = 0; -SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, - CTLFLAG_RW, &ip_acceptsourceroute, 0, - "Enable accepting source routed IP packets"); - -int ip_doopts = 1; /* 0 = ignore, 1 = process, 2 = reject */ -SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW, - &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)"); - static int ip_keepfaith = 0; SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, &ip_keepfaith, 0, @@ -218,25 +206,6 @@ ip_dn_io_t *ip_dn_io_ptr = NULL; int fw_enable = 1; int fw_one_pass = 1; -/* - * XXX this is ugly. IP options source routing magic. - */ -struct ipoptrt { - struct in_addr dst; /* final destination */ - char nop; /* one NOP to align */ - char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ - struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; -}; - -struct ipopt_tag { - struct m_tag tag; - int ip_nhops; - struct ipoptrt ip_srcrt; -}; - -static void save_rte(struct mbuf *, u_char *, struct in_addr); -static int ip_dooptions(struct mbuf *m, int); -static void ip_forward(struct mbuf *m, int srcrt); static void ip_freef(struct ipqhead *, struct ipq *); /* @@ -1239,289 +1208,6 @@ ipproto_unregister(u_char ipproto) return (0); } - -/* - * Do option processing on a datagram, - * possibly discarding it if bad options are encountered, - * or forwarding it if source-routed. - * The pass argument is used when operating in the IPSTEALTH - * mode to tell what options to process: - * [LS]SRR (pass 0) or the others (pass 1). - * The reason for as many as two passes is that when doing IPSTEALTH, - * non-routing options should be processed only if the packet is for us. - * Returns 1 if packet has been forwarded/freed, - * 0 if the packet should be processed further. - */ -static int -ip_dooptions(struct mbuf *m, int pass) -{ - struct ip *ip = mtod(m, struct ip *); - u_char *cp; - struct in_ifaddr *ia; - int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; - struct in_addr *sin, dst; - n_time ntime; - struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; - - /* ignore or reject packets with IP options */ - if (ip_doopts == 0) - return 0; - else if (ip_doopts == 2) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_FILTER_PROHIB; - goto bad; - } - - dst = ip->ip_dst; - cp = (u_char *)(ip + 1); - cnt = (ip->ip_hl << 2) - sizeof (struct ip); - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) - optlen = 1; - else { - if (cnt < IPOPT_OLEN + sizeof(*cp)) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - optlen = cp[IPOPT_OLEN]; - if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - } - switch (opt) { - - default: - break; - - /* - * Source routing with record. - * Find interface with current destination address. - * If none on this machine then drop if strictly routed, - * or do nothing if loosely routed. - * Record interface address and bring up next address - * component. If strictly routed make sure next - * address is on directly accessible net. - */ - case IPOPT_LSRR: - case IPOPT_SSRR: -#ifdef IPSTEALTH - if (ipstealth && pass > 0) - break; -#endif - if (optlen < IPOPT_OFFSET + sizeof(*cp)) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - ipaddr.sin_addr = ip->ip_dst; - ia = (struct in_ifaddr *) - ifa_ifwithaddr((struct sockaddr *)&ipaddr); - if (ia == NULL) { - if (opt == IPOPT_SSRR) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - if (!ip_dosourceroute) - goto nosourcerouting; - /* - * Loose routing, and not at next destination - * yet; nothing to do except forward. - */ - break; - } - off--; /* 0 origin */ - if (off > optlen - (int)sizeof(struct in_addr)) { - /* - * End of source route. Should be for us. - */ - if (!ip_acceptsourceroute) - goto nosourcerouting; - save_rte(m, cp, ip->ip_src); - break; - } -#ifdef IPSTEALTH - if (ipstealth) - goto dropit; -#endif - if (!ip_dosourceroute) { - if (ipforwarding) { - char buf[16]; /* aaa.bbb.ccc.ddd\0 */ - /* - * Acting as a router, so generate ICMP - */ -nosourcerouting: - strcpy(buf, inet_ntoa(ip->ip_dst)); - log(LOG_WARNING, - "attempted source route from %s to %s\n", - inet_ntoa(ip->ip_src), buf); - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } else { - /* - * Not acting as a router, so silently drop. - */ -#ifdef IPSTEALTH -dropit: -#endif - ipstat.ips_cantforward++; - m_freem(m); - return (1); - } - } - - /* - * locate outgoing interface - */ - (void)memcpy(&ipaddr.sin_addr, cp + off, - sizeof(ipaddr.sin_addr)); - - if (opt == IPOPT_SSRR) { -#define INA struct in_ifaddr * -#define SA struct sockaddr * - if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL) - ia = (INA)ifa_ifwithnet((SA)&ipaddr); - } else - ia = ip_rtaddr(ipaddr.sin_addr); - if (ia == NULL) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - ip->ip_dst = ipaddr.sin_addr; - (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), - sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - /* - * Let ip_intr's mcast routing check handle mcast pkts - */ - forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); - break; - - case IPOPT_RR: -#ifdef IPSTEALTH - if (ipstealth && pass == 0) - break; -#endif - if (optlen < IPOPT_OFFSET + sizeof(*cp)) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - /* - * If no space remains, ignore. - */ - off--; /* 0 origin */ - if (off > optlen - (int)sizeof(struct in_addr)) - break; - (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, - sizeof(ipaddr.sin_addr)); - /* - * locate outgoing interface; if we're the destination, - * use the incoming interface (should be same). - */ - if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL && - (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_HOST; - goto bad; - } - (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), - sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - break; - - case IPOPT_TS: -#ifdef IPSTEALTH - if (ipstealth && pass == 0) - break; -#endif - code = cp - (u_char *)ip; - if (optlen < 4 || optlen > 40) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - if ((off = cp[IPOPT_OFFSET]) < 5) { - code = &cp[IPOPT_OLEN] - (u_char *)ip; - goto bad; - } - if (off > optlen - (int)sizeof(int32_t)) { - cp[IPOPT_OFFSET + 1] += (1 << 4); - if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - break; - } - off--; /* 0 origin */ - sin = (struct in_addr *)(cp + off); - switch (cp[IPOPT_OFFSET + 1] & 0x0f) { - - case IPOPT_TS_TSONLY: - break; - - case IPOPT_TS_TSANDADDR: - if (off + sizeof(n_time) + - sizeof(struct in_addr) > optlen) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - ipaddr.sin_addr = dst; - ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, - m->m_pkthdr.rcvif); - if (ia == NULL) - continue; - (void)memcpy(sin, &IA_SIN(ia)->sin_addr, - sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - off += sizeof(struct in_addr); - break; - - case IPOPT_TS_PRESPEC: - if (off + sizeof(n_time) + - sizeof(struct in_addr) > optlen) { - code = &cp[IPOPT_OFFSET] - (u_char *)ip; - goto bad; - } - (void)memcpy(&ipaddr.sin_addr, sin, - sizeof(struct in_addr)); - if (ifa_ifwithaddr((SA)&ipaddr) == NULL) - continue; - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - off += sizeof(struct in_addr); - break; - - default: - code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; - goto bad; - } - ntime = iptime(); - (void)memcpy(cp + off, &ntime, sizeof(n_time)); - cp[IPOPT_OFFSET] += sizeof(n_time); - } - } - if (forward && ipforwarding) { - ip_forward(m, 1); - return (1); - } - return (0); -bad: - icmp_error(m, type, code, 0, 0); - ipstat.ips_badoptions++; - return (1); -} - /* * Given address of next destination (final or next hop), * return internet address info of interface to be used to get there. @@ -1549,143 +1235,6 @@ ip_rtaddr(dst) return (ifa); } -/* - * Save incoming source route for use in replies, - * to be picked up later by ip_srcroute if the receiver is interested. - */ -static void -save_rte(m, option, dst) - struct mbuf *m; - u_char *option; - struct in_addr dst; -{ - unsigned olen; - struct ipopt_tag *opts; - - opts = (struct ipopt_tag *)m_tag_get(PACKET_TAG_IPOPTIONS, - sizeof(struct ipopt_tag), M_NOWAIT); - if (opts == NULL) - return; - - olen = option[IPOPT_OLEN]; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf("save_rte: olen %d\n", olen); -#endif - if (olen > sizeof(opts->ip_srcrt) - (1 + sizeof(dst))) { - m_tag_free((struct m_tag *)opts); - return; - } - bcopy(option, opts->ip_srcrt.srcopt, olen); - opts->ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); - opts->ip_srcrt.dst = dst; - m_tag_prepend(m, (struct m_tag *)opts); -} - -/* - * Retrieve incoming source route for use in replies, - * in the same form used by setsockopt. - * The first hop is placed before the options, will be removed later. - */ -struct mbuf * -ip_srcroute(m0) - struct mbuf *m0; -{ - register struct in_addr *p, *q; - register struct mbuf *m; - struct ipopt_tag *opts; - - opts = (struct ipopt_tag *)m_tag_find(m0, PACKET_TAG_IPOPTIONS, NULL); - if (opts == NULL) - return (NULL); - - if (opts->ip_nhops == 0) - return (NULL); - m = m_get(M_DONTWAIT, MT_DATA); - if (m == NULL) - return (NULL); - -#define OPTSIZ (sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt)) - - /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ - m->m_len = opts->ip_nhops * sizeof(struct in_addr) + - sizeof(struct in_addr) + OPTSIZ; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf("ip_srcroute: nhops %d mlen %d", opts->ip_nhops, m->m_len); -#endif - - /* - * First save first hop for return route - */ - p = &(opts->ip_srcrt.route[opts->ip_nhops - 1]); - *(mtod(m, struct in_addr *)) = *p--; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); -#endif - - /* - * Copy option fields and padding (nop) to mbuf. - */ - opts->ip_srcrt.nop = IPOPT_NOP; - opts->ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; - (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), - &(opts->ip_srcrt.nop), OPTSIZ); - q = (struct in_addr *)(mtod(m, caddr_t) + - sizeof(struct in_addr) + OPTSIZ); -#undef OPTSIZ - /* - * Record return path as an IP source route, - * reversing the path (pointers are now aligned). - */ - while (p >= opts->ip_srcrt.route) { -#ifdef DIAGNOSTIC - if (ipprintfs) - printf(" %lx", (u_long)ntohl(q->s_addr)); -#endif - *q++ = *p--; - } - /* - * Last hop goes to final destination. - */ - *q = opts->ip_srcrt.dst; -#ifdef DIAGNOSTIC - if (ipprintfs) - printf(" %lx\n", (u_long)ntohl(q->s_addr)); -#endif - m_tag_delete(m0, (struct m_tag *)opts); - return (m); -} - -/* - * Strip out IP options, at higher - * level protocol in the kernel. - * Second argument is buffer to which options - * will be moved, and return value is their length. - * XXX should be deleted; last arg currently ignored. - */ -void -ip_stripoptions(m, mopt) - register struct mbuf *m; - struct mbuf *mopt; -{ - register int i; - struct ip *ip = mtod(m, struct ip *); - register caddr_t opts; - int olen; - - olen = (ip->ip_hl << 2) - sizeof (struct ip); - opts = (caddr_t)(ip + 1); - i = m->m_len - (sizeof (struct ip) + olen); - bcopy(opts + olen, opts, (unsigned)i); - m->m_len -= olen; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len -= olen; - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(struct ip) >> 2; -} - u_char inetctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 1c0f6a810642..c50466fe88b6 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -90,6 +90,7 @@ #include #include #include +#include #ifdef PIM #include #include diff --git a/sys/netinet/ip_options.c b/sys/netinet/ip_options.c new file mode 100644 index 000000000000..2b993067b10b --- /dev/null +++ b/sys/netinet/ip_options.c @@ -0,0 +1,708 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2005 + * Andre Oppermann, Internet Business Solutions AG. All right reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_ipstealth.h" +#include "opt_mac.h" + +#include +#include +#include +#include +/* #include */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int ip_dosourceroute = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, + &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); + +static int ip_acceptsourceroute = 0; +SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, + CTLFLAG_RW, &ip_acceptsourceroute, 0, + "Enable accepting source routed IP packets"); + +int ip_doopts = 1; /* 0 = ignore, 1 = process, 2 = reject */ +SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW, + &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)"); + +static void save_rte(struct mbuf *m, u_char *, struct in_addr); + +/* + * Do option processing on a datagram, + * possibly discarding it if bad options are encountered, + * or forwarding it if source-routed. + * The pass argument is used when operating in the IPSTEALTH + * mode to tell what options to process: + * [LS]SRR (pass 0) or the others (pass 1). + * The reason for as many as two passes is that when doing IPSTEALTH, + * non-routing options should be processed only if the packet is for us. + * Returns 1 if packet has been forwarded/freed, + * 0 if the packet should be processed further. + */ +int +ip_dooptions(struct mbuf *m, int pass) +{ + struct ip *ip = mtod(m, struct ip *); + u_char *cp; + struct in_ifaddr *ia; + int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; + struct in_addr *sin, dst; + n_time ntime; + struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; + + /* ignore or reject packets with IP options */ + if (ip_doopts == 0) + return 0; + else if (ip_doopts == 2) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_FILTER_PROHIB; + goto bad; + } + + dst = ip->ip_dst; + cp = (u_char *)(ip + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + if (cnt < IPOPT_OLEN + sizeof(*cp)) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + optlen = cp[IPOPT_OLEN]; + if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + } + switch (opt) { + + default: + break; + + /* + * Source routing with record. + * Find interface with current destination address. + * If none on this machine then drop if strictly routed, + * or do nothing if loosely routed. + * Record interface address and bring up next address + * component. If strictly routed make sure next + * address is on directly accessible net. + */ + case IPOPT_LSRR: + case IPOPT_SSRR: +#ifdef IPSTEALTH + if (ipstealth && pass > 0) + break; +#endif + if (optlen < IPOPT_OFFSET + sizeof(*cp)) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = ip->ip_dst; + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)&ipaddr); + if (ia == NULL) { + if (opt == IPOPT_SSRR) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + if (!ip_dosourceroute) + goto nosourcerouting; + /* + * Loose routing, and not at next destination + * yet; nothing to do except forward. + */ + break; + } + off--; /* 0 origin */ + if (off > optlen - (int)sizeof(struct in_addr)) { + /* + * End of source route. Should be for us. + */ + if (!ip_acceptsourceroute) + goto nosourcerouting; + save_rte(m, cp, ip->ip_src); + break; + } +#ifdef IPSTEALTH + if (ipstealth) + goto dropit; +#endif + if (!ip_dosourceroute) { + if (ipforwarding) { + char buf[16]; /* aaa.bbb.ccc.ddd\0 */ + /* + * Acting as a router, so generate ICMP + */ +nosourcerouting: + strcpy(buf, inet_ntoa(ip->ip_dst)); + log(LOG_WARNING, + "attempted source route from %s to %s\n", + inet_ntoa(ip->ip_src), buf); + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } else { + /* + * Not acting as a router, so silently drop. + */ +#ifdef IPSTEALTH +dropit: +#endif + ipstat.ips_cantforward++; + m_freem(m); + return (1); + } + } + + /* + * locate outgoing interface + */ + (void)memcpy(&ipaddr.sin_addr, cp + off, + sizeof(ipaddr.sin_addr)); + + if (opt == IPOPT_SSRR) { +#define INA struct in_ifaddr * +#define SA struct sockaddr * + if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL) + ia = (INA)ifa_ifwithnet((SA)&ipaddr); + } else + ia = ip_rtaddr(ipaddr.sin_addr); + if (ia == NULL) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + ip->ip_dst = ipaddr.sin_addr; + (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), + sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); + break; + + case IPOPT_RR: +#ifdef IPSTEALTH + if (ipstealth && pass == 0) + break; +#endif + if (optlen < IPOPT_OFFSET + sizeof(*cp)) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + /* + * If no space remains, ignore. + */ + off--; /* 0 origin */ + if (off > optlen - (int)sizeof(struct in_addr)) + break; + (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, + sizeof(ipaddr.sin_addr)); + /* + * locate outgoing interface; if we're the destination, + * use the incoming interface (should be same). + */ + if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL && + (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), + sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + break; + + case IPOPT_TS: +#ifdef IPSTEALTH + if (ipstealth && pass == 0) + break; +#endif + code = cp - (u_char *)ip; + if (optlen < 4 || optlen > 40) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + if ((off = cp[IPOPT_OFFSET]) < 5) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + if (off > optlen - (int)sizeof(int32_t)) { + cp[IPOPT_OFFSET + 1] += (1 << 4); + if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + break; + } + off--; /* 0 origin */ + sin = (struct in_addr *)(cp + off); + switch (cp[IPOPT_OFFSET + 1] & 0x0f) { + + case IPOPT_TS_TSONLY: + break; + + case IPOPT_TS_TSANDADDR: + if (off + sizeof(n_time) + + sizeof(struct in_addr) > optlen) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == NULL) + continue; + (void)memcpy(sin, &IA_SIN(ia)->sin_addr, + sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + off += sizeof(struct in_addr); + break; + + case IPOPT_TS_PRESPEC: + if (off + sizeof(n_time) + + sizeof(struct in_addr) > optlen) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + (void)memcpy(&ipaddr.sin_addr, sin, + sizeof(struct in_addr)); + if (ifa_ifwithaddr((SA)&ipaddr) == NULL) + continue; + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + off += sizeof(struct in_addr); + break; + + default: + code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; + goto bad; + } + ntime = iptime(); + (void)memcpy(cp + off, &ntime, sizeof(n_time)); + cp[IPOPT_OFFSET] += sizeof(n_time); + } + } + if (forward && ipforwarding) { + ip_forward(m, 1); + return (1); + } + return (0); +bad: + icmp_error(m, type, code, 0, 0); + ipstat.ips_badoptions++; + return (1); +} + +/* + * Save incoming source route for use in replies, + * to be picked up later by ip_srcroute if the receiver is interested. + */ +static void +save_rte(m, option, dst) + struct mbuf *m; + u_char *option; + struct in_addr dst; +{ + unsigned olen; + struct ipopt_tag *opts; + + opts = (struct ipopt_tag *)m_tag_get(PACKET_TAG_IPOPTIONS, + sizeof(struct ipopt_tag), M_NOWAIT); + if (opts == NULL) + return; + + olen = option[IPOPT_OLEN]; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf("save_rte: olen %d\n", olen); +#endif + if (olen > sizeof(opts->ip_srcrt) - (1 + sizeof(dst))) { + m_tag_free((struct m_tag *)opts); + return; + } + bcopy(option, opts->ip_srcrt.srcopt, olen); + opts->ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); + opts->ip_srcrt.dst = dst; + m_tag_prepend(m, (struct m_tag *)opts); +} + +/* + * Retrieve incoming source route for use in replies, + * in the same form used by setsockopt. + * The first hop is placed before the options, will be removed later. + */ +struct mbuf * +ip_srcroute(m0) + struct mbuf *m0; +{ + register struct in_addr *p, *q; + register struct mbuf *m; + struct ipopt_tag *opts; + + opts = (struct ipopt_tag *)m_tag_find(m0, PACKET_TAG_IPOPTIONS, NULL); + if (opts == NULL) + return (NULL); + + if (opts->ip_nhops == 0) + return (NULL); + m = m_get(M_DONTWAIT, MT_DATA); + if (m == NULL) + return (NULL); + +#define OPTSIZ (sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt)) + + /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ + m->m_len = opts->ip_nhops * sizeof(struct in_addr) + + sizeof(struct in_addr) + OPTSIZ; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf("ip_srcroute: nhops %d mlen %d", opts->ip_nhops, m->m_len); +#endif + + /* + * First save first hop for return route + */ + p = &(opts->ip_srcrt.route[opts->ip_nhops - 1]); + *(mtod(m, struct in_addr *)) = *p--; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); +#endif + + /* + * Copy option fields and padding (nop) to mbuf. + */ + opts->ip_srcrt.nop = IPOPT_NOP; + opts->ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; + (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), + &(opts->ip_srcrt.nop), OPTSIZ); + q = (struct in_addr *)(mtod(m, caddr_t) + + sizeof(struct in_addr) + OPTSIZ); +#undef OPTSIZ + /* + * Record return path as an IP source route, + * reversing the path (pointers are now aligned). + */ + while (p >= opts->ip_srcrt.route) { +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" %lx", (u_long)ntohl(q->s_addr)); +#endif + *q++ = *p--; + } + /* + * Last hop goes to final destination. + */ + *q = opts->ip_srcrt.dst; +#ifdef DIAGNOSTIC + if (ipprintfs) + printf(" %lx\n", (u_long)ntohl(q->s_addr)); +#endif + m_tag_delete(m0, (struct m_tag *)opts); + return (m); +} + +/* + * Strip out IP options, at higher + * level protocol in the kernel. + * Second argument is buffer to which options + * will be moved, and return value is their length. + * XXX should be deleted; last arg currently ignored. + */ +void +ip_stripoptions(m, mopt) + register struct mbuf *m; + struct mbuf *mopt; +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register caddr_t opts; + int olen; + + olen = (ip->ip_hl << 2) - sizeof (struct ip); + opts = (caddr_t)(ip + 1); + i = m->m_len - (sizeof (struct ip) + olen); + bcopy(opts + olen, opts, (unsigned)i); + m->m_len -= olen; + if (m->m_flags & M_PKTHDR) + m->m_pkthdr.len -= olen; + ip->ip_v = IPVERSION; + ip->ip_hl = sizeof(struct ip) >> 2; +} + +/* + * Insert IP options into preformed packet. + * Adjust IP destination as required for IP source routing, + * as indicated by a non-zero in_addr at the start of the options. + * + * XXX This routine assumes that the packet has no options in place. + */ +struct mbuf * +ip_insertoptions(m, opt, phlen) + register struct mbuf *m; + struct mbuf *opt; + int *phlen; +{ + register struct ipoption *p = mtod(opt, struct ipoption *); + struct mbuf *n; + register struct ip *ip = mtod(m, struct ip *); + unsigned optlen; + + optlen = opt->m_len - sizeof(p->ipopt_dst); + if (optlen + ip->ip_len > IP_MAXPACKET) { + *phlen = 0; + return (m); /* XXX should fail */ + } + if (p->ipopt_dst.s_addr) + ip->ip_dst = p->ipopt_dst; + if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n == NULL) { + *phlen = 0; + return (m); + } + M_MOVE_PKTHDR(n, m); + n->m_pkthdr.rcvif = NULL; +#ifdef MAC + mac_copy_mbuf(m, n); +#endif + n->m_pkthdr.len += optlen; + m->m_len -= sizeof(struct ip); + m->m_data += sizeof(struct ip); + n->m_next = m; + m = n; + m->m_len = optlen + sizeof(struct ip); + m->m_data += max_linkhdr; + bcopy(ip, mtod(m, void *), sizeof(struct ip)); + } else { + m->m_data -= optlen; + m->m_len += optlen; + m->m_pkthdr.len += optlen; + bcopy(ip, mtod(m, void *), sizeof(struct ip)); + } + ip = mtod(m, struct ip *); + bcopy(p->ipopt_list, ip + 1, optlen); + *phlen = sizeof(struct ip) + optlen; + ip->ip_v = IPVERSION; + ip->ip_hl = *phlen >> 2; + ip->ip_len += optlen; + return (m); +} + +/* + * Copy options from ip to jp, + * omitting those not copied during fragmentation. + */ +int +ip_optcopy(ip, jp) + struct ip *ip, *jp; +{ + register u_char *cp, *dp; + int opt, optlen, cnt; + + cp = (u_char *)(ip + 1); + dp = (u_char *)(jp + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) { + /* Preserve for IP mcast tunnel's LSRR alignment. */ + *dp++ = IPOPT_NOP; + optlen = 1; + continue; + } + + KASSERT(cnt >= IPOPT_OLEN + sizeof(*cp), + ("ip_optcopy: malformed ipv4 option")); + optlen = cp[IPOPT_OLEN]; + KASSERT(optlen >= IPOPT_OLEN + sizeof(*cp) && optlen <= cnt, + ("ip_optcopy: malformed ipv4 option")); + + /* bogus lengths should have been caught by ip_dooptions */ + if (optlen > cnt) + optlen = cnt; + if (IPOPT_COPIED(opt)) { + bcopy(cp, dp, optlen); + dp += optlen; + } + } + for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) + *dp++ = IPOPT_EOL; + return (optlen); +} + +/* + * Set up IP options in pcb for insertion in output packets. + * Store in mbuf with pointer in pcbopt, adding pseudo-option + * with destination address if source routed. + */ +int +ip_pcbopts(struct inpcb *inp, int optname, struct mbuf *m) +{ + register int cnt, optlen; + register u_char *cp; + struct mbuf **pcbopt; + u_char opt; + + INP_LOCK_ASSERT(inp); + + pcbopt = &inp->inp_options; + + /* turn off any old options */ + if (*pcbopt) + (void)m_free(*pcbopt); + *pcbopt = 0; + if (m == NULL || m->m_len == 0) { + /* + * Only turning off any previous options. + */ + if (m != NULL) + (void)m_free(m); + return (0); + } + + if (m->m_len % sizeof(int32_t)) + goto bad; + /* + * IP first-hop destination address will be stored before + * actual options; move other options back + * and clear it when none present. + */ + if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) + goto bad; + cnt = m->m_len; + m->m_len += sizeof(struct in_addr); + cp = mtod(m, u_char *) + sizeof(struct in_addr); + bcopy(mtod(m, void *), cp, (unsigned)cnt); + bzero(mtod(m, void *), sizeof(struct in_addr)); + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + if (cnt < IPOPT_OLEN + sizeof(*cp)) + goto bad; + optlen = cp[IPOPT_OLEN]; + if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) + goto bad; + } + switch (opt) { + + default: + break; + + case IPOPT_LSRR: + case IPOPT_SSRR: + /* + * user process specifies route as: + * ->A->B->C->D + * D must be our final destination (but we can't + * check that since we may not have connected yet). + * A is first hop destination, which doesn't appear in + * actual IP option, but is stored before the options. + */ + if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) + goto bad; + m->m_len -= sizeof(struct in_addr); + cnt -= sizeof(struct in_addr); + optlen -= sizeof(struct in_addr); + cp[IPOPT_OLEN] = optlen; + /* + * Move first hop before start of options. + */ + bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), + sizeof(struct in_addr)); + /* + * Then copy rest of options back + * to close up the deleted entry. + */ + bcopy((&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)), + &cp[IPOPT_OFFSET+1], + (unsigned)cnt - (IPOPT_MINOFF - 1)); + break; + } + } + if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) + goto bad; + *pcbopt = m; + return (0); + +bad: + (void)m_free(m); + return (EINVAL); +} diff --git a/sys/netinet/ip_options.h b/sys/netinet/ip_options.h new file mode 100644 index 000000000000..b7c00500f8ed --- /dev/null +++ b/sys/netinet/ip_options.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2005 + * Andre Oppermann, Internet Business Solutions AG. All right reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _NETINET_IP_OPTIONS_H_ +#define _NETINET_IP_OPTIONS_H_ + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoptrt { + struct in_addr dst; /* final destination */ + char nop; /* one NOP to align */ + char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ + struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; +}; + +struct ipopt_tag { + struct m_tag tag; /* m_tag */ + int ip_nhops; + struct ipoptrt ip_srcrt; +}; + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + char ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +extern int ip_doopts; /* process or ignore IP options */ + +int ip_dooptions(struct mbuf *, int); +struct mbuf * + ip_insertoptions(struct mbuf *, struct mbuf *, int *); +int ip_optcopy(struct ip *, struct ip *); +int ip_pcbopts(struct inpcb *, int, struct mbuf *); +void ip_stripoptions(struct mbuf *, struct mbuf *); +struct mbuf * + ip_srcroute(struct mbuf *); + +#endif /* !_NETINET_IP_OPTIONS_H_ */ diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index edd49e1c9861..6e4388e79a36 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -57,6 +57,7 @@ #include #include #include +#include #include @@ -92,16 +93,11 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, mbuf_frag_size, CTLFLAG_RW, &mbuf_frag_size, 0, "Fragment outgoing mbufs to this size"); #endif -static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *); static struct ifnet *ip_multicast_if(struct in_addr *, int *); static void ip_mloopback (struct ifnet *, struct mbuf *, struct sockaddr_in *, int); static int ip_getmoptions(struct inpcb *, struct sockopt *); -static int ip_pcbopts(struct inpcb *, int, struct mbuf *); static int ip_setmoptions(struct inpcb *, struct sockopt *); -static struct ip_moptions *ip_findmoptions(struct inpcb *inp); - -int ip_optcopy(struct ip *, struct ip *); extern struct protosw inetsw[]; @@ -1052,109 +1048,6 @@ in_delayed_cksum(struct mbuf *m) *(u_short *)(m->m_data + offset) = csum; } -/* - * Insert IP options into preformed packet. - * Adjust IP destination as required for IP source routing, - * as indicated by a non-zero in_addr at the start of the options. - * - * XXX This routine assumes that the packet has no options in place. - */ -static struct mbuf * -ip_insertoptions(m, opt, phlen) - register struct mbuf *m; - struct mbuf *opt; - int *phlen; -{ - register struct ipoption *p = mtod(opt, struct ipoption *); - struct mbuf *n; - register struct ip *ip = mtod(m, struct ip *); - unsigned optlen; - - optlen = opt->m_len - sizeof(p->ipopt_dst); - if (optlen + ip->ip_len > IP_MAXPACKET) { - *phlen = 0; - return (m); /* XXX should fail */ - } - if (p->ipopt_dst.s_addr) - ip->ip_dst = p->ipopt_dst; - if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n == NULL) { - *phlen = 0; - return (m); - } - M_MOVE_PKTHDR(n, m); - n->m_pkthdr.rcvif = NULL; -#ifdef MAC - mac_copy_mbuf(m, n); -#endif - n->m_pkthdr.len += optlen; - m->m_len -= sizeof(struct ip); - m->m_data += sizeof(struct ip); - n->m_next = m; - m = n; - m->m_len = optlen + sizeof(struct ip); - m->m_data += max_linkhdr; - bcopy(ip, mtod(m, void *), sizeof(struct ip)); - } else { - m->m_data -= optlen; - m->m_len += optlen; - m->m_pkthdr.len += optlen; - bcopy(ip, mtod(m, void *), sizeof(struct ip)); - } - ip = mtod(m, struct ip *); - bcopy(p->ipopt_list, ip + 1, optlen); - *phlen = sizeof(struct ip) + optlen; - ip->ip_v = IPVERSION; - ip->ip_hl = *phlen >> 2; - ip->ip_len += optlen; - return (m); -} - -/* - * Copy options from ip to jp, - * omitting those not copied during fragmentation. - */ -int -ip_optcopy(ip, jp) - struct ip *ip, *jp; -{ - register u_char *cp, *dp; - int opt, optlen, cnt; - - cp = (u_char *)(ip + 1); - dp = (u_char *)(jp + 1); - cnt = (ip->ip_hl << 2) - sizeof (struct ip); - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[0]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) { - /* Preserve for IP mcast tunnel's LSRR alignment. */ - *dp++ = IPOPT_NOP; - optlen = 1; - continue; - } - - KASSERT(cnt >= IPOPT_OLEN + sizeof(*cp), - ("ip_optcopy: malformed ipv4 option")); - optlen = cp[IPOPT_OLEN]; - KASSERT(optlen >= IPOPT_OLEN + sizeof(*cp) && optlen <= cnt, - ("ip_optcopy: malformed ipv4 option")); - - /* bogus lengths should have been caught by ip_dooptions */ - if (optlen > cnt) - optlen = cnt; - if (IPOPT_COPIED(opt)) { - bcopy(cp, dp, optlen); - dp += optlen; - } - } - for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) - *dp++ = IPOPT_EOL; - return (optlen); -} - /* * IP socket option processing. */ @@ -1464,110 +1357,6 @@ ip_ctloutput(so, sopt) return (error); } -/* - * Set up IP options in pcb for insertion in output packets. - * Store in mbuf with pointer in pcbopt, adding pseudo-option - * with destination address if source routed. - */ -static int -ip_pcbopts(struct inpcb *inp, int optname, struct mbuf *m) -{ - register int cnt, optlen; - register u_char *cp; - struct mbuf **pcbopt; - u_char opt; - - INP_LOCK_ASSERT(inp); - - pcbopt = &inp->inp_options; - - /* turn off any old options */ - if (*pcbopt) - (void)m_free(*pcbopt); - *pcbopt = 0; - if (m == NULL || m->m_len == 0) { - /* - * Only turning off any previous options. - */ - if (m != NULL) - (void)m_free(m); - return (0); - } - - if (m->m_len % sizeof(int32_t)) - goto bad; - /* - * IP first-hop destination address will be stored before - * actual options; move other options back - * and clear it when none present. - */ - if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) - goto bad; - cnt = m->m_len; - m->m_len += sizeof(struct in_addr); - cp = mtod(m, u_char *) + sizeof(struct in_addr); - bcopy(mtod(m, void *), cp, (unsigned)cnt); - bzero(mtod(m, void *), sizeof(struct in_addr)); - - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) - optlen = 1; - else { - if (cnt < IPOPT_OLEN + sizeof(*cp)) - goto bad; - optlen = cp[IPOPT_OLEN]; - if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) - goto bad; - } - switch (opt) { - - default: - break; - - case IPOPT_LSRR: - case IPOPT_SSRR: - /* - * user process specifies route as: - * ->A->B->C->D - * D must be our final destination (but we can't - * check that since we may not have connected yet). - * A is first hop destination, which doesn't appear in - * actual IP option, but is stored before the options. - */ - if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) - goto bad; - m->m_len -= sizeof(struct in_addr); - cnt -= sizeof(struct in_addr); - optlen -= sizeof(struct in_addr); - cp[IPOPT_OLEN] = optlen; - /* - * Move first hop before start of options. - */ - bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), - sizeof(struct in_addr)); - /* - * Then copy rest of options back - * to close up the deleted entry. - */ - bcopy((&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)), - &cp[IPOPT_OFFSET+1], - (unsigned)cnt - (IPOPT_MINOFF - 1)); - break; - } - } - if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) - goto bad; - *pcbopt = m; - return (0); - -bad: - (void)m_free(m); - return (EINVAL); -} - /* * XXX * The whole multicast option thing needs to be re-thought. diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index e64570b0aeff..49a6f9a92f2a 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -65,19 +65,6 @@ struct ipq { }; #endif /* _KERNEL */ -/* - * Structure stored in mbuf in inpcb.ip_options - * and passed to ip_output when ip options are in use. - * The actual length of the options (including ipopt_dst) - * is in m_len. - */ -#define MAX_IPOPTLEN 40 - -struct ipoption { - struct in_addr ipopt_dst; /* first-hop dst if source routed */ - char ipopt_list[MAX_IPOPTLEN]; /* options proper */ -}; - /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. @@ -151,7 +138,6 @@ extern struct ipstat ipstat; extern u_short ip_id; /* ip packet ctr, for ids */ extern int ip_defttl; /* default IP ttl */ extern int ipforwarding; /* ip forwarding */ -extern int ip_doopts; /* process or ignore IP options */ #ifdef IPSTEALTH extern int ipstealth; /* stealth forwarding */ #endif @@ -169,6 +155,7 @@ void ip_fini(void *xtp); int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, u_long if_hwassist_flags, int sw_csum); void ip_freemoptions(struct ip_moptions *); +void ip_forward(struct mbuf *m, int srcrt); void ip_init(void); extern int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *, struct ip_moptions *); @@ -184,9 +171,6 @@ struct in_ifaddr * void ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *, struct mbuf *); void ip_slowtimo(void); -struct mbuf * - ip_srcroute(struct mbuf *); -void ip_stripoptions(struct mbuf *, struct mbuf *); u_int16_t ip_randomid(void); int rip_ctloutput(struct socket *, struct sockopt *); void rip_ctlinput(int, struct sockaddr *, void *); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 7e2eba42e10b..c62752d634aa 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -68,6 +68,7 @@ #include /* for ICMP_BANDLIM */ #include /* for ICMP_BANDLIM */ #include +#include #include #include #include diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index e377bdf95e47..f68c2d9c12e4 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -57,6 +57,7 @@ #include #include #include +#include #ifdef INET6 #include #include diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 7e2eba42e10b..c62752d634aa 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -68,6 +68,7 @@ #include /* for ICMP_BANDLIM */ #include /* for ICMP_BANDLIM */ #include +#include #include #include #include diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index c92f9222ba0e..87d919aed8e6 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -60,6 +60,7 @@ #include #include #include +#include #ifdef INET6 #include #include diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index ca0cdb9660a8..c422c8ff8135 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -68,6 +68,7 @@ #include #include #include +#include #ifdef INET6 #include #endif