diff options
author | andre <andre@FreeBSD.org> | 2005-11-18 20:12:40 +0000 |
---|---|---|
committer | andre <andre@FreeBSD.org> | 2005-11-18 20:12:40 +0000 |
commit | a6a209f2cc1f1d34f8b16c17f8cb345db2ecbe99 (patch) | |
tree | 2177105da5828491dd19a0aad0cf83477925d06f /sys/netinet/ip_input.c | |
parent | 50b1ba762b66c4f2056c0aa72e275ba857413419 (diff) | |
download | FreeBSD-src-a6a209f2cc1f1d34f8b16c17f8cb345db2ecbe99.zip FreeBSD-src-a6a209f2cc1f1d34f8b16c17f8cb345db2ecbe99.tar.gz |
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
Diffstat (limited to 'sys/netinet/ip_input.c')
-rw-r--r-- | sys/netinet/ip_input.c | 453 |
1 files changed, 1 insertions, 452 deletions
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f84b562..75563f0 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -66,6 +66,7 @@ #include <netinet/in_pcb.h> #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> +#include <netinet/ip_options.h> #include <machine/in_cksum.h> #ifdef DEV_CARP #include <netinet/ip_carp.h> @@ -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, |