summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files1
-rw-r--r--sys/netinet/igmp.c1
-rw-r--r--sys/netinet/ip_fastfwd.c1
-rw-r--r--sys/netinet/ip_icmp.c1
-rw-r--r--sys/netinet/ip_input.c453
-rw-r--r--sys/netinet/ip_mroute.c1
-rw-r--r--sys/netinet/ip_options.c708
-rw-r--r--sys/netinet/ip_options.h74
-rw-r--r--sys/netinet/ip_output.c213
-rw-r--r--sys/netinet/ip_var.h18
-rw-r--r--sys/netinet/tcp_input.c1
-rw-r--r--sys/netinet/tcp_output.c1
-rw-r--r--sys/netinet/tcp_reass.c1
-rw-r--r--sys/netinet/tcp_syncache.c1
-rw-r--r--sys/netinet/udp_usrreq.c1
15 files changed, 795 insertions, 681 deletions
diff --git a/sys/conf/files b/sys/conf/files
index d029f9f..0650ad9 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 ea93c2e..d82727d 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -65,6 +65,7 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#include <netinet/igmp.h>
#include <netinet/igmp_var.h>
diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c
index 1f5f535..43419f3 100644
--- a/sys/netinet/ip_fastfwd.c
+++ b/sys/netinet/ip_fastfwd.c
@@ -100,6 +100,7 @@
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
+#include <netinet/ip_options.h>
#include <machine/in_cksum.h>
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index dd7e125..0d3131a 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -54,6 +54,7 @@
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#include <netinet/tcp.h>
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
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,
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 1c0f6a8..c50466f 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -90,6 +90,7 @@
#include <netinet/ip_encap.h>
#include <netinet/ip_mroute.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#ifdef PIM
#include <netinet/pim.h>
#include <netinet/pim_var.h>
diff --git a/sys/netinet/ip_options.c b/sys/netinet/ip_options.c
new file mode 100644
index 0000000..2b99306
--- /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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mac.h>
+#include <sys/mbuf.h>
+/* #include <sys/malloc.h> */
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/netisr.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
+#include <netinet/ip_icmp.h>
+#include <machine/in_cksum.h>
+
+#include <sys/socketvar.h>
+
+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 0000000..b7c0050
--- /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 edd49e1..6e4388e 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -57,6 +57,7 @@
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#include <machine/in_cksum.h>
@@ -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[];
@@ -1053,109 +1049,6 @@ in_delayed_cksum(struct mbuf *m)
}
/*
- * 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.
*/
int
@@ -1465,110 +1358,6 @@ ip_ctloutput(so, sopt)
}
/*
- * 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.
* Several of these options are equally applicable to non-multicast
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index e64570b..49a6f9a 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -66,19 +66,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 7e2eba4..c62752d 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -68,6 +68,7 @@
#include <netinet/ip_icmp.h> /* for ICMP_BANDLIM */
#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/in6_pcb.h>
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index e377bdf..f68c2d9 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -57,6 +57,7 @@
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
#include <netinet/ip6.h>
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 7e2eba4..c62752d 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -68,6 +68,7 @@
#include <netinet/ip_icmp.h> /* for ICMP_BANDLIM */
#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/in6_pcb.h>
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index c92f922..87d919a 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -60,6 +60,7 @@
#include <netinet/in_var.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index ca0cdb9..c422c8f 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -68,6 +68,7 @@
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <netinet/ip_var.h>
+#include <netinet/ip_options.h>
#ifdef INET6
#include <netinet6/ip6_var.h>
#endif
OpenPOWER on IntegriCloud