summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_input.c
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2005-11-18 20:12:40 +0000
committerandre <andre@FreeBSD.org>2005-11-18 20:12:40 +0000
commita6a209f2cc1f1d34f8b16c17f8cb345db2ecbe99 (patch)
tree2177105da5828491dd19a0aad0cf83477925d06f /sys/netinet/ip_input.c
parent50b1ba762b66c4f2056c0aa72e275ba857413419 (diff)
downloadFreeBSD-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.c453
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,
OpenPOWER on IntegriCloud