summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/bridge.c87
-rw-r--r--sys/net/if_ethersubr.c67
-rw-r--r--sys/netinet/ip_divert.c131
-rw-r--r--sys/netinet/ip_dummynet.c85
-rw-r--r--sys/netinet/ip_dummynet.h40
-rw-r--r--sys/netinet/ip_fw.c80
-rw-r--r--sys/netinet/ip_fw.h25
-rw-r--r--sys/netinet/ip_input.c224
-rw-r--r--sys/netinet/ip_output.c218
-rw-r--r--sys/netinet/ip_var.h3
-rw-r--r--sys/netinet/tcp_input.c23
-rw-r--r--sys/netinet/tcp_reass.c23
12 files changed, 532 insertions, 474 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c
index 48a31cc..6fc888e 100644
--- a/sys/net/bridge.c
+++ b/sys/net/bridge.c
@@ -793,12 +793,12 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh)
static struct mbuf *
bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
{
- struct ifnet *src = m0->m_pkthdr.rcvif; /* NULL when called by *_output */
- struct ifnet *ifp, *last = NULL ;
+ struct ifnet *src;
+ struct ifnet *ifp, *last;
int shared = bdg_copy ; /* someone else is using the mbuf */
int once = 0; /* loop only once */
struct ifnet *real_dst = dst ; /* real dst from ether_output */
- struct ip_fw *rule = NULL ; /* did we match a firewall rule ? */
+ struct ip_fw_args args;
#ifdef PFIL_HOOKS
struct packet_filter_hook *pfh;
int rv;
@@ -813,16 +813,18 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
DEB(quad_t ticks; ticks = rdtsc();)
- if (m0->m_type == MT_DUMMYNET) {
- /* extract info from dummynet header */
- rule = (struct ip_fw *)(m0->m_data) ;
- m0 = m0->m_next ;
- src = m0->m_pkthdr.rcvif;
- shared = 0 ; /* For sure this is our own mbuf. */
- } else
- bdg_thru++; /* count packet, only once */
+ args.rule = NULL; /* did we match a firewall rule ? */
+ /* Fetch state from dummynet tag, ignore others */
+ for (;m0->m_type == MT_TAG; m0 = m0->m_next)
+ if (m0->m_tag_id == PACKET_TAG_DUMMYNET) {
+ args.rule = ((struct dn_pkt *)m0)->rule;
+ shared = 0; /* For sure this is our own mbuf. */
+ }
+ if (args.rule == NULL)
+ bdg_thru++; /* first time through bdg_forward, count packet */
- if (src == NULL) /* packet from ether_output */
+ src = m0->m_pkthdr.rcvif;
+ if (src == NULL) /* packet from ether_output */
dst = bridge_dst_lookup(eh, ifp2sc[real_dst->if_index].cluster);
if (dst == BDG_DROP) { /* this should not happen */
@@ -861,7 +863,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
int i;
- if (rule != NULL) /* dummynet packet, already partially processed */
+ if (args.rule != NULL) /* packet already partially processed */
goto forward; /* HACK! I should obey the fw_one_pass */
/*
* i need some amt of data to be contiguous, and in case others need
@@ -910,15 +912,24 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
#endif /* PFIL_HOOKS */
/*
- * The second parameter to the firewall code is the dst. interface.
- * Since we apply checks only on input pkts we use NULL.
- * The firewall knows this is a bridged packet as the cookie ptr
- * is NULL.
+ * Prepare arguments and call the firewall.
*/
if (!IPFW_LOADED || bdg_ipfw == 0)
goto forward; /* not using ipfw, accept the packet */
- i = ip_fw_chk_ptr(&m0, NULL, NULL /* cookie */, &rule,
- (struct sockaddr_in **)&save_eh);
+
+ /*
+ * XXX The following code is very similar to the one in
+ * if_ethersubr.c:ether_ipfw_chk()
+ */
+
+ args.m = m0; /* the packet we are looking at */
+ args.oif = NULL; /* this is an input packet */
+ args.divert_rule = 0; /* we do not support divert yet */
+ args.next_hop = NULL; /* we do not support forward yet */
+ args.eh = &save_eh; /* MAC header for bridged/MAC packets */
+ i = ip_fw_chk_ptr(&args);
+ m0 = args.m; /* in case the firewall used the mbuf */
+
if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */
return m0 ;
@@ -928,20 +939,21 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
/*
* Pass the pkt to dummynet, which consumes it.
* If shared, make a copy and keep the original.
- * Need to prepend the ethernet header, optimize the common
- * case of eh pointing already into the original mbuf.
*/
struct mbuf *m ;
+
if (shared) {
m = m_copypacket(m0, M_DONTWAIT);
- if (m == NULL) {
- printf("bdg_fwd: copy(1) failed\n");
+ if (m == NULL) /* copy failed, give up */
return m0;
- }
} else {
m = m0 ; /* pass the original to dummynet */
m0 = NULL ; /* and nothing back to the caller */
}
+ /*
+ * Prepend the header, optimize for the common case of
+ * eh pointing into the mbuf.
+ */
if ( (void *)(eh + 1) == (void *)m->m_data) {
m->m_data -= ETHER_HDR_LEN ;
m->m_len += ETHER_HDR_LEN ;
@@ -949,21 +961,20 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
bdg_predict++;
} else {
M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
- if (!m && verbose)
- printf("M_PREPEND failed\n");
if (m == NULL) /* nope... */
return m0 ;
bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN);
}
- ip_dn_io_ptr((i & 0xffff),DN_TO_BDG_FWD,m,real_dst,NULL,0,rule,0);
+
+ args.oif = real_dst;
+ ip_dn_io_ptr(m, (i & 0xffff),DN_TO_BDG_FWD, &args);
return m0 ;
}
/*
- * XXX add divert/forward actions...
+ * XXX at some point, add support for divert/forward actions.
+ * If none of the above matches, we have to drop the packet.
*/
- /* if none of the above matches, we have to drop the pkt */
bdg_ipfw_drops++ ;
- printf("bdg_forward: No rules match, so dropping packet!\n");
return m0 ;
}
forward:
@@ -975,14 +986,20 @@ forward:
int i = min(m0->m_pkthdr.len, max_protohdr) ;
m0 = m_pullup(m0, i) ;
- if (m0 == NULL) {
- printf("-- bdg: pullup2 failed.\n") ;
+ if (m0 == NULL)
return NULL ;
- }
}
- /* now real_dst is used to determine the cluster where to forward */
- if (src != NULL) /* pkt comes from ether_input */
+ /*
+ * now real_dst is used to determine the cluster where to forward.
+ * For packets coming from ether_input, this is the one of the 'src'
+ * interface, whereas for locally generated packets (src==NULL) it
+ * is the cluster of the original destination interface, which
+ * was already saved into real_dst.
+ */
+ if (src != NULL)
real_dst = src ;
+
+ last = NULL;
for (;;) {
if (last) { /* need to forward packet leftover from previous loop */
struct mbuf *m ;
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 16fb62f..ad3db35 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -383,15 +383,16 @@ ether_output_frame(ifp, m)
struct mbuf *m;
{
int error = 0;
-
-#if 1 /* XXX ipfw */
struct ip_fw *rule = NULL;
- if (m->m_type == MT_DUMMYNET) { /* extract info from dummynet header */
- rule = (struct ip_fw *)(m->m_data) ;
- m = m->m_next ;
+
+ /* Extract info from dummynet tag, ignore others */
+ for (; m->m_type == MT_TAG; m = m->m_next)
+ if (m->m_flags == PACKET_TAG_DUMMYNET)
+ rule = ((struct dn_pkt *)m)->rule;
+
+ if (rule) /* packet was already bridged */
goto no_bridge;
- }
-#endif
+
if (BDG_ACTIVE(ifp) ) {
struct ether_header *eh; /* a ptr suffices */
@@ -404,7 +405,6 @@ ether_output_frame(ifp, m)
return (0);
}
-#if 1 /* XXX ipfw */
no_bridge:
if (IPFW_LOADED && ether_ipfw != 0) {
struct ether_header save_eh, *eh;
@@ -432,7 +432,7 @@ no_bridge:
ETHER_HDR_LEN);
}
}
-#endif /* XXX ipfw */
+
/*
* Queue message on interface, update output statistics if
* successful, and start output if interface not yet active.
@@ -454,7 +454,8 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst,
struct ip_fw **rule, struct ether_header *eh, int shared)
{
struct ether_header save_eh = *eh; /* could be a ptr in m */
- int i;
+ int i;
+ struct ip_fw_args args;
if (*rule != NULL) /* dummynet packet, already partially processed */
return 1; /* HACK! I should obey the fw_one_pass */
@@ -465,14 +466,20 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst,
i = min( (*m0)->m_pkthdr.len, max_protohdr) ;
if ( shared || (*m0)->m_len < i) {
*m0 = m_pullup(*m0, i);
- if (*m0 == NULL) {
- printf("-- bdg: pullup failed.\n") ;
+ if (*m0 == NULL)
return 0;
- }
}
- i = ip_fw_chk_ptr(m0, dst, NULL /* cookie */, rule,
- (struct sockaddr_in **)&save_eh);
+ args.m = *m0; /* the packet we are looking at */
+ args.oif = dst; /* destination, if any */
+ args.divert_rule = 0; /* we do not support divert yet */
+ args.rule = *rule; /* matching rule to restart */
+ args.next_hop = NULL; /* we do not support forward yet */
+ args.eh = &save_eh; /* MAC header for bridged/MAC packets */
+ i = ip_fw_chk_ptr(&args);
+ *m0 = args.m;
+ *rule = args.rule;
+
if ( (i & IP_FW_PORT_DENY_FLAG) || *m0 == NULL) /* drop */
return 0;
@@ -483,21 +490,21 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst,
/*
* Pass the pkt to dummynet, which consumes it.
* If shared, make a copy and keep the original.
- * Need to prepend the ethernet header, optimize the common
- * case of eh pointing already into the original mbuf.
*/
struct mbuf *m ;
if (shared) {
m = m_copypacket(*m0, M_DONTWAIT);
- if (m == NULL) {
- printf("bdg_fwd: copy(1) failed\n");
+ if (m == NULL)
return 0;
- }
} else {
m = *m0 ; /* pass the original to dummynet */
*m0 = NULL ; /* and nothing back to the caller */
}
+ /*
+ * Prepend the header, optimize for the common case of
+ * eh pointing into the mbuf.
+ */
if ( (void *)(eh + 1) == (void *)m->m_data) {
m->m_data -= ETHER_HDR_LEN ;
m->m_len += ETHER_HDR_LEN ;
@@ -509,8 +516,8 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst,
bcopy(&save_eh, mtod(m, struct ether_header *),
ETHER_HDR_LEN);
}
- ip_dn_io_ptr((i & 0xffff), dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX,
- m, dst, NULL /*route*/, 0 /*dst*/, *rule, 0 /*flags*/);
+ ip_dn_io_ptr(m, (i & 0xffff),
+ dst ? DN_TO_ETH_OUT: DN_TO_ETH_DEMUX, &args);
return 0;
}
/*
@@ -627,15 +634,17 @@ ether_demux(ifp, eh, m)
register struct llc *l;
#endif
-#if 1 /* XXX ipfw */
struct ip_fw *rule = NULL;
- if (m->m_type == MT_DUMMYNET) { /* extract info from dummynet header */
- rule = (struct ip_fw *)(m->m_data) ;
- m = m->m_next ;
- ifp = m->m_pkthdr.rcvif;
+
+ /* Extract info from dummynet tag, ignore others */
+ for (;m->m_type == MT_TAG; m = m->m_next)
+ if (m->m_flags == PACKET_TAG_DUMMYNET) {
+ rule = ((struct dn_pkt *)m)->rule;
+ ifp = m->m_next->m_pkthdr.rcvif;
+ }
+
+ if (rule) /* packet was already bridged */
goto post_stats;
- }
-#endif
if (! (BDG_ACTIVE(ifp) ) )
/* Discard packet if upper layers shouldn't see it because it was
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index d0dfd1f..e58f079 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -79,20 +79,28 @@
#define DIVRCVQ (65536 + 100)
/*
- * A 16 bit cookie is passed to and from the user process.
- * The user process can send it back to help the caller know
- * something about where the packet originally came from.
+ * Divert sockets work in conjunction with ipfw, see the divert(4)
+ * manpage for features.
+ * Internally, packets selected by ipfw in ip_input() or ip_output(),
+ * and never diverted before, are passed to the input queue of the
+ * divert socket with a given 'divert_port' number (as specified in
+ * the matching ipfw rule), and they are tagged with a 16 bit cookie
+ * (representing the rule number of the matching ipfw rule), which
+ * is passed to process reading from the socket.
*
- * In the case of ipfw, then the cookie is the rule that sent
- * us here. On reinjection is is the rule after which processing
- * should continue. Leaving it the same will make processing start
- * at the rule number after that which sent it here. Setting it to
- * 0 will restart processing at the beginning.
+ * Packets written to the divert socket are again tagged with a cookie
+ * (usually the same as above) and a destination address.
+ * If the destination address is INADDR_ANY then the packet is
+ * treated as outgoing and sent to ip_output(), otherwise it is
+ * treated as incoming and sent to ip_input().
+ * In both cases, the packet is tagged with the cookie.
*
- * For divert_packet(), ip_divert_cookie is an input value only.
- * For div_output(), ip_divert_cookie is an output value only.
+ * On reinjection, processing in ip_input() and ip_output()
+ * will be exactly the same as for the original packet, except that
+ * ipfw processing will start at the rule number after the one
+ * written in the cookie (so, tagging a packet with a cookie of 0
+ * will cause it to be effectively considered as a standard packet).
*/
-u_int16_t ip_divert_cookie;
/* Internal variables */
static struct inpcbhead divcb;
@@ -104,10 +112,6 @@ static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */
/* Optimization: have this preinitialized */
static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
-/* Internal functions */
-static int div_output(struct socket *so,
- struct mbuf *m, struct sockaddr *addr, struct mbuf *control);
-
/*
* Initialize divert connection block queue.
*/
@@ -147,7 +151,7 @@ div_input(struct mbuf *m, int off)
* then pass them along with mbuf chain.
*/
void
-divert_packet(struct mbuf *m, int incoming, int port)
+divert_packet(struct mbuf *m, int incoming, int port, int rule)
{
struct ip *ip;
struct inpcb *inp;
@@ -157,15 +161,12 @@ divert_packet(struct mbuf *m, int incoming, int port)
/* Sanity check */
KASSERT(port != 0, ("%s: port=0", __func__));
- /* Record and reset divert cookie */
- divsrc.sin_port = ip_divert_cookie;
- ip_divert_cookie = 0;
+ divsrc.sin_port = rule; /* record matching rule */
/* Assure header */
if (m->m_len < sizeof(struct ip) &&
- (m = m_pullup(m, sizeof(struct ip))) == 0) {
+ (m = m_pullup(m, sizeof(struct ip))) == 0)
return;
- }
ip = mtod(m, struct ip *);
/*
@@ -246,45 +247,48 @@ divert_packet(struct mbuf *m, int incoming, int port)
* the interface with that address.
*/
static int
-div_output(so, m, addr, control)
- struct socket *so;
- register struct mbuf *m;
- struct sockaddr *addr;
- struct mbuf *control;
+div_output(struct socket *so, struct mbuf *m,
+ struct sockaddr_in *sin, struct mbuf *control)
{
- register struct inpcb *const inp = sotoinpcb(so);
- register struct ip *const ip = mtod(m, struct ip *);
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
int error = 0;
+ struct m_hdr divert_tag;
+
+ /*
+ * Prepare the tag for divert info. Note that a packet
+ * with a 0 tag in mh_data is effectively untagged,
+ * so we could optimize that case.
+ */
+ divert_tag.mh_type = MT_TAG;
+ divert_tag.mh_flags = PACKET_TAG_DIVERT;
+ divert_tag.mh_next = m;
+ divert_tag.mh_data = 0; /* the matching rule # */
+ m->m_pkthdr.rcvif = NULL; /* XXX is it necessary ? */
if (control)
m_freem(control); /* XXX */
/* Loopback avoidance and state recovery */
if (sin) {
- int len = 0;
- char *c = sin->sin_zero;
-
- ip_divert_cookie = sin->sin_port;
+ int i;
+ divert_tag.mh_data = (caddr_t)(int)sin->sin_port;
/*
- * Find receive interface with the given name or IP address.
- * The name is user supplied data so don't trust it's size or
- * that it is zero terminated. The name has priority.
- * We are presently assuming that the sockaddr_in
- * has not been replaced by a sockaddr_div, so we limit it
- * to 16 bytes in total. the name is stuffed (if it exists)
- * in the sin_zero[] field.
+ * Find receive interface with the given name, stuffed
+ * (if it exists) in the sin_zero[] field.
+ * The name is user supplied data so don't trust its size
+ * or that it is zero terminated.
*/
- while (*c++ && (len++ < sizeof(sin->sin_zero)));
- if ((len > 0) && (len < sizeof(sin->sin_zero)))
+ for (i = 0; sin->sin_zero[i] && i < sizeof(sin->sin_zero); i++)
+ ;
+ if ( i > 0 && i < sizeof(sin->sin_zero))
m->m_pkthdr.rcvif = ifunit(sin->sin_zero);
- } else {
- ip_divert_cookie = 0;
}
/* Reinject packet into the system as incoming or outgoing */
if (!sin || sin->sin_addr.s_addr == 0) {
+ struct inpcb *const inp = sotoinpcb(so);
+ struct ip *const ip = mtod(m, struct ip *);
+
/*
* Don't allow both user specified and setsockopt options,
* and don't allow packet length sizes that will crash
@@ -301,42 +305,37 @@ div_output(so, m, addr, control)
/* Send packet to output processing */
ipstat.ips_rawout++; /* XXX */
- error = ip_output(m, inp->inp_options, &inp->inp_route,
- (so->so_options & SO_DONTROUTE) |
- IP_ALLOWBROADCAST | IP_RAWOUTPUT,
- inp->inp_moptions);
+ error = ip_output((struct mbuf *)&divert_tag,
+ inp->inp_options, &inp->inp_route,
+ (so->so_options & SO_DONTROUTE) |
+ IP_ALLOWBROADCAST | IP_RAWOUTPUT,
+ inp->inp_moptions);
} else {
- struct ifaddr *ifa;
-
- /* If no luck with the name above. check by IP address. */
if (m->m_pkthdr.rcvif == NULL) {
/*
- * Make sure there are no distractions
- * for ifa_ifwithaddr. Clear the port and the ifname.
- * Maybe zap all 8 bytes at once using a 64bit write?
+ * No luck with the name, check by IP address.
+ * Clear the port and the ifname to make sure
+ * there are no distractions for ifa_ifwithaddr.
*/
+ struct ifaddr *ifa;
+
bzero(sin->sin_zero, sizeof(sin->sin_zero));
- /* *((u_int64_t *)sin->sin_zero) = 0; */ /* XXX ?? */
sin->sin_port = 0;
- if (!(ifa = ifa_ifwithaddr((struct sockaddr *) sin))) {
+ ifa = ifa_ifwithaddr((struct sockaddr *) sin);
+ if (ifa == NULL) {
error = EADDRNOTAVAIL;
goto cantsend;
}
m->m_pkthdr.rcvif = ifa->ifa_ifp;
}
-
/* Send packet to input processing */
- ip_input(m);
+ ip_input((struct mbuf *)&divert_tag);
}
- /* paranoid: Reset for next time (and other packets) */
- /* almost definitly already done in the ipfw filter but.. */
- ip_divert_cookie = 0;
return error;
cantsend:
m_freem(m);
- ip_divert_cookie = 0;
return error;
}
@@ -406,16 +405,16 @@ div_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
s = splnet();
inp = sotoinpcb(so);
- /* in_pcbbind assumes that the socket is a sockaddr_in
+ /* in_pcbbind assumes that the nam is a sockaddr_in
* and in_pcbbind requires a valid address. Since divert
* sockets don't we need to make sure the address is
* filled in properly.
* XXX -- divert should not be abusing in_pcbind
* and should probably have its own family.
*/
- if (nam->sa_family != AF_INET) {
+ if (nam->sa_family != AF_INET)
error = EAFNOSUPPORT;
- } else {
+ else {
((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY;
error = in_pcbbind(inp, nam, td);
}
@@ -443,7 +442,7 @@ div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
}
/* Send packet */
- return div_output(so, m, nam, control);
+ return div_output(so, m, (struct sockaddr_in *)nam, control);
}
static int
diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c
index fa7fd91..6006b65 100644
--- a/sys/netinet/ip_dummynet.c
+++ b/sys/netinet/ip_dummynet.c
@@ -161,9 +161,7 @@ static void rt_unref(struct rtentry *);
static void dummynet(void *);
static void dummynet_flush(void);
void dummynet_drain(void);
-static int dummynet_io(int pipe_nr, int dir, struct mbuf *m, struct ifnet *ifp,
- struct route *ro, struct sockaddr_in * dst,
- struct ip_fw *rule, int flags);
+static ip_dn_io_t dummynet_io;
static void dn_rule_delete(void *);
int if_tx_rdy(struct ifnet *ifp);
@@ -423,9 +421,8 @@ transmit_event(struct dn_pipe *pipe)
/*
* The actual mbuf is preceded by a struct dn_pkt, resembling an mbuf
* (NOT A REAL one, just a small block of malloc'ed memory) with
- * m_type = MT_DUMMYNET
- * m_next = actual mbuf to be processed by ip_input/output
- * m_data = the matching rule
+ * m_type = MT_TAG, m_flags = PACKET_TAG_DUMMYNET
+ * dn_m (m_next) = actual mbuf to be processed by ip_input/output
* and some other fields.
* The block IS FREED HERE because it contains parameters passed
* to the called routine.
@@ -862,7 +859,7 @@ create_queue(struct dn_flow_set *fs, int i)
* so that further searches take less time.
*/
static struct dn_flow_queue *
-find_queue(struct dn_flow_set *fs)
+find_queue(struct dn_flow_set *fs, struct ipfw_flow_id *id)
{
int i = 0 ; /* we need i and q for new allocations */
struct dn_flow_queue *q, *prev;
@@ -871,25 +868,25 @@ find_queue(struct dn_flow_set *fs)
q = fs->rq[0] ;
else {
/* first, do the masking */
- last_pkt.dst_ip &= fs->flow_mask.dst_ip ;
- last_pkt.src_ip &= fs->flow_mask.src_ip ;
- last_pkt.dst_port &= fs->flow_mask.dst_port ;
- last_pkt.src_port &= fs->flow_mask.src_port ;
- last_pkt.proto &= fs->flow_mask.proto ;
- last_pkt.flags = 0 ; /* we don't care about this one */
+ id->dst_ip &= fs->flow_mask.dst_ip ;
+ id->src_ip &= fs->flow_mask.src_ip ;
+ id->dst_port &= fs->flow_mask.dst_port ;
+ id->src_port &= fs->flow_mask.src_port ;
+ id->proto &= fs->flow_mask.proto ;
+ id->flags = 0 ; /* we don't care about this one */
/* then, hash function */
- i = ( (last_pkt.dst_ip) & 0xffff ) ^
- ( (last_pkt.dst_ip >> 15) & 0xffff ) ^
- ( (last_pkt.src_ip << 1) & 0xffff ) ^
- ( (last_pkt.src_ip >> 16 ) & 0xffff ) ^
- (last_pkt.dst_port << 1) ^ (last_pkt.src_port) ^
- (last_pkt.proto );
+ i = ( (id->dst_ip) & 0xffff ) ^
+ ( (id->dst_ip >> 15) & 0xffff ) ^
+ ( (id->src_ip << 1) & 0xffff ) ^
+ ( (id->src_ip >> 16 ) & 0xffff ) ^
+ (id->dst_port << 1) ^ (id->src_port) ^
+ (id->proto );
i = i % fs->rq_size ;
/* finally, scan the current list for a match */
searches++ ;
for (prev=NULL, q = fs->rq[i] ; q ; ) {
search_steps++;
- if (bcmp(&last_pkt, &(q->id), sizeof(q->id) ) == 0)
+ if (bcmp(id, &(q->id), sizeof(q->id) ) == 0)
break ; /* found */
else if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
/* entry is idle and not in any heap, expire it */
@@ -915,7 +912,7 @@ find_queue(struct dn_flow_set *fs)
if (q == NULL) { /* no match, need to allocate a new entry */
q = create_queue(fs, i);
if (q != NULL)
- q->id = last_pkt ;
+ q->id = *id ;
}
return q ;
}
@@ -1059,11 +1056,8 @@ locate_flowset(int pipe_nr, struct ip_fw *rule)
* flags flags from the caller, only used in ip_output
*
*/
-int
-dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
- struct mbuf *m, struct ifnet *ifp, struct route *ro,
- struct sockaddr_in *dst,
- struct ip_fw *rule, int flags)
+static int
+dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
{
struct dn_pkt *pkt;
struct dn_flow_set *fs;
@@ -1076,8 +1070,8 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
pipe_nr &= 0xffff ;
- if ( (fs = rule->pipe_ptr) == NULL ) {
- fs = locate_flowset(pipe_nr, rule);
+ if ( (fs = fwa->rule->pipe_ptr) == NULL ) {
+ fs = locate_flowset(pipe_nr, fwa->rule);
if (fs == NULL)
goto dropit ; /* this queue/pipe does not exist! */
}
@@ -1094,7 +1088,7 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
goto dropit ;
}
}
- q = find_queue(fs);
+ q = find_queue(fs, &(fwa->f_id));
if ( q == NULL )
goto dropit ; /* cannot allocate queue */
/*
@@ -1120,27 +1114,28 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
goto dropit ; /* cannot allocate packet header */
/* ok, i can handle the pkt now... */
/* build and enqueue packet + parameters */
- pkt->hdr.mh_type = MT_DUMMYNET ;
- (struct ip_fw *)pkt->hdr.mh_data = rule ;
+ pkt->hdr.mh_type = MT_TAG;
+ pkt->hdr.mh_flags = PACKET_TAG_DUMMYNET;
+ pkt->rule = fwa->rule ;
DN_NEXT(pkt) = NULL;
pkt->dn_m = m;
pkt->dn_dir = dir ;
- pkt->ifp = ifp;
+ pkt->ifp = fwa->oif;
if (dir == DN_TO_IP_OUT) {
/*
* We need to copy *ro because for ICMP pkts (and maybe others)
* the caller passed a pointer into the stack; dst might also be
* a pointer into *ro so it needs to be updated.
*/
- pkt->ro = *ro;
- if (ro->ro_rt)
- ro->ro_rt->rt_refcnt++ ;
- if (dst == (struct sockaddr_in *)&ro->ro_dst) /* dst points into ro */
- dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ;
-
- pkt->dn_dst = dst;
- pkt->flags = flags ;
+ pkt->ro = *(fwa->ro);
+ if (fwa->ro->ro_rt)
+ fwa->ro->ro_rt->rt_refcnt++ ;
+ if (fwa->dst == (struct sockaddr_in *)&fwa->ro->ro_dst) /* dst points into ro */
+ fwa->dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ;
+
+ pkt->dn_dst = fwa->dst;
+ pkt->flags = fwa->flags;
}
if (q->head == NULL)
q->head = pkt;
@@ -1157,7 +1152,7 @@ dummynet_io(int pipe_nr, int dir, /* pipe_nr can also be a fs_nr */
* to schedule it. This involves different actions for fixed-rate or
* WF2Q queues.
*/
- if ( (rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_PIPE ) {
+ if ( (fwa->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_PIPE ) {
/*
* Fixed-rate queue: just insert into the ready_heap.
*/
@@ -1355,8 +1350,8 @@ dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
for (i = 0 ; i <= fs->rq_size ; i++) /* last one is ovflow */
for (q = fs->rq[i] ; q ; q = q->next )
for (pkt = q->head ; pkt ; pkt = DN_NEXT(pkt) )
- if (pkt->hdr.mh_data == r)
- pkt->hdr.mh_data = (void *)ip_fw_default_rule ;
+ if (pkt->rule == r)
+ pkt->rule = ip_fw_default_rule ;
}
/*
* when a firewall rule is deleted, scan all queues and remove the flow-id
@@ -1380,8 +1375,8 @@ dn_rule_delete(void *r)
fs = &(p->fs) ;
dn_rule_delete_fs(fs, r);
for (pkt = p->head ; pkt ; pkt = DN_NEXT(pkt) )
- if (pkt->hdr.mh_data == r)
- pkt->hdr.mh_data = (void *)ip_fw_default_rule ;
+ if (pkt->rule == r)
+ pkt->rule = ip_fw_default_rule ;
}
}
diff --git a/sys/netinet/ip_dummynet.h b/sys/netinet/ip_dummynet.h
index ff482d7..3453517 100644
--- a/sys/netinet/ip_dummynet.h
+++ b/sys/netinet/ip_dummynet.h
@@ -104,36 +104,33 @@ struct dn_heap {
} ;
/*
- * MT_DUMMYNET is a new (fake) mbuf type that is prepended to the
- * packet when it comes out of a pipe. The definition
- * ought to go in /sys/sys/mbuf.h but here it is less intrusive.
- */
-
-#define MT_DUMMYNET MT_CONTROL
-
-/*
- * struct dn_pkt identifies a packet in the dummynet queue. The
- * first part is really an m_hdr for implementation purposes, and some
- * fields are saved there. When passing the packet back to the ip_input/
- * ip_output()/bdg_forward, the struct is prepended to the mbuf chain with type
- * MT_DUMMYNET, and contains the pointer to the matching rule.
+ * struct dn_pkt identifies a packet in the dummynet queue, but
+ * is also used to tag packets passed back to the various destinations
+ * (ip_input(), ip_output(), bdg_forward() and so on).
+ * As such the first part of the structure must be a struct m_hdr,
+ * followed by dummynet-specific parameters. The m_hdr must be
+ * initialized with
+ * mh_type = MT_TAG;
+ * mh_flags = PACKET_TYPE_DUMMYNET;
+ * mh_next = <pointer to the actual mbuf>
*
- * Note: there is no real need to make this structure contain an m_hdr,
- * in the future this should be changed to a normal data structure.
+ * mh_nextpkt, mh_data are free for dummynet use (mh_nextpkt is used to
+ * build a linked list of packets in a dummynet queue).
*/
struct dn_pkt {
struct m_hdr hdr ;
-#define dn_next hdr.mh_nextpkt /* next element in queue */
-#define DN_NEXT(x) (struct dn_pkt *)(x)->dn_next
+#define DN_NEXT(x) (struct dn_pkt *)(x)->hdr.mh_nextpkt
#define dn_m hdr.mh_next /* packet to be forwarded */
-#define dn_dir hdr.mh_flags /* action when pkt extracted from a queue */
+
+ struct ip_fw *rule; /* matching rule */
+ int dn_dir; /* action when packet comes out. */
#define DN_TO_IP_OUT 1
#define DN_TO_IP_IN 2
#define DN_TO_BDG_FWD 3
#define DN_TO_ETH_DEMUX 4
#define DN_TO_ETH_OUT 5
- dn_key output_time; /* when the pkt is due for delivery */
+ dn_key output_time; /* when the pkt is due for delivery */
struct ifnet *ifp; /* interface, for ip_output */
struct sockaddr_in *dn_dst ;
struct route ro; /* route, for ip_output. MUST COPY */
@@ -351,9 +348,8 @@ struct dn_pipe { /* a pipe */
#ifdef _KERNEL
typedef int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */
typedef void ip_dn_ruledel_t(void *); /* ip_fw.c */
-typedef int ip_dn_io_t(int pipe, int dir, struct mbuf *m,
- struct ifnet *ifp, struct route *ro, struct sockaddr_in * dst,
- struct ip_fw *rule, int flags); /* ip_{in,out}put.c, bridge.c */
+typedef int ip_dn_io_t(struct mbuf *m, int pipe_nr, int dir,
+ struct ip_fw_args *fwa);
extern ip_dn_ctl_t *ip_dn_ctl_ptr;
extern ip_dn_ruledel_t *ip_dn_ruledel_ptr;
extern ip_dn_io_t *ip_dn_io_ptr;
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index 016022e..d7ccad7 100644
--- a/sys/netinet/ip_fw.c
+++ b/sys/netinet/ip_fw.c
@@ -86,7 +86,6 @@ static int fw_permanent_rules = 0;
*/
static u_int64_t counter; /* counter for ipfw_report(NULL...) */
-struct ipfw_flow_id last_pkt ;
#define IPFW_DEFAULT_RULE ((u_int)(u_short)~0)
@@ -567,7 +566,7 @@ ipfw_report(struct ip_fw *f, struct ip *ip, int ip_off, int ip_len,
snprintf(SNPARGS(action2, 0), "Queue %d",
f->fw_skipto_rule);
break;
-#ifdef IPFIREWALL_FORWARD
+
case IP_FW_F_FWD:
if (f->fw_fwd_ip.sin_port)
snprintf(SNPARGS(action2, 0),
@@ -578,7 +577,7 @@ ipfw_report(struct ip_fw *f, struct ip *ip, int ip_off, int ip_len,
snprintf(SNPARGS(action2, 0), "Forward to %s",
inet_ntoa(f->fw_fwd_ip.sin_addr));
break;
-#endif
+
default:
action = "UNKNOWN";
break;
@@ -954,7 +953,7 @@ lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
* session limitations are enforced.
*/
static int
-install_state(struct ip_fw *rule)
+install_state(struct ip_fw *rule, struct ip_fw_args *args)
{
struct ipfw_dyn_rule *q ;
static int last_log ;
@@ -963,10 +962,10 @@ install_state(struct ip_fw *rule)
DEB(printf("-- install state type %d 0x%08x %u -> 0x%08x %u\n",
type,
- (last_pkt.src_ip), (last_pkt.src_port),
- (last_pkt.dst_ip), (last_pkt.dst_port) );)
+ (args->f_id.src_ip), (args->f_id.src_port),
+ (args->f_id.dst_ip), (args->f_id.dst_port) );)
- q = lookup_dyn_rule(&last_pkt, NULL) ;
+ q = lookup_dyn_rule(&args->f_id, NULL) ;
if (q != NULL) { /* should never occur */
if (last_log != time_second) {
last_log = time_second ;
@@ -986,7 +985,7 @@ install_state(struct ip_fw *rule)
switch (type) {
case DYN_KEEP_STATE: /* bidir rule */
- add_dyn_rule(&last_pkt, DYN_KEEP_STATE, rule);
+ add_dyn_rule(&args->f_id, DYN_KEEP_STATE, rule);
break ;
case DYN_LIMIT: /* limit number of sessions */
{
@@ -999,16 +998,16 @@ install_state(struct ip_fw *rule)
id.dst_ip = id.src_ip = 0;
id.dst_port = id.src_port = 0 ;
- id.proto = last_pkt.proto ;
+ id.proto = args->f_id.proto ;
if (limit_mask & DYN_SRC_ADDR)
- id.src_ip = last_pkt.src_ip;
+ id.src_ip = args->f_id.src_ip;
if (limit_mask & DYN_DST_ADDR)
- id.dst_ip = last_pkt.dst_ip;
+ id.dst_ip = args->f_id.dst_ip;
if (limit_mask & DYN_SRC_PORT)
- id.src_port = last_pkt.src_port;
+ id.src_port = args->f_id.src_port;
if (limit_mask & DYN_DST_PORT)
- id.dst_port = last_pkt.dst_port;
+ id.dst_port = args->f_id.dst_port;
parent = lookup_dyn_parent(&id, rule);
if (parent == NULL) {
printf("add parent failed\n");
@@ -1021,14 +1020,14 @@ install_state(struct ip_fw *rule)
return 1;
}
}
- add_dyn_rule(&last_pkt, DYN_LIMIT, (struct ip_fw *)parent);
+ add_dyn_rule(&args->f_id, DYN_LIMIT, (struct ip_fw *)parent);
}
break ;
default:
printf("unknown dynamic rule type %u\n", type);
return 1 ;
}
- lookup_dyn_rule(&last_pkt, NULL) ; /* XXX just set the lifetime */
+ lookup_dyn_rule(&args->f_id, NULL) ; /* XXX just set the lifetime */
return 0;
}
@@ -1083,9 +1082,22 @@ lookup_next_rule(struct ip_fw *me)
*/
static int
-ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie,
+ip_fw_chk(struct ip_fw_args *args)
+#if 0 /* the old interface was this: */
+ struct mbuf **m, struct ifnet *oif, u_int16_t *cookie,
struct ip_fw **flow_id, struct sockaddr_in **next_hop)
+#endif
{
+ /*
+ * grab things into variables to minimize diffs.
+ * XXX this has to be cleaned up later.
+ */
+ struct mbuf **m = &(args->m);
+ struct ifnet *oif = args->oif;
+ u_int16_t *cookie = &(args->divert_rule);
+ struct ip_fw **flow_id = &(args->rule);
+ struct sockaddr_in **next_hop = &(args->next_hop);
+
struct ip_fw *f = NULL; /* matching rule */
struct ip *ip = mtod(*m, struct ip *);
struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
@@ -1099,18 +1111,16 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie,
struct in_addr src_ip, dst_ip;
u_int8_t proto= 0, flags = 0;
- u_int16_t skipto, bridgeCookie;
+ u_int16_t skipto;
u_int16_t ip_len=0;
int dyn_checked = 0 ; /* set after dyn.rules have been checked. */
int direction = MATCH_FORWARD ; /* dirty trick... */
struct ipfw_dyn_rule *q = NULL ;
-#define BRIDGED (cookie == &bridgeCookie)
- if (cookie == NULL) { /* this is a bridged packet */
- bridgeCookie = 0;
- cookie = &bridgeCookie;
- eh = (struct ether_header *)next_hop;
+#define BRIDGED (args->eh != NULL)
+ if (BRIDGED) { /* this is a bridged packet */
+ eh = args->eh;
if ( (*m)->m_pkthdr.len >= sizeof(struct ip) &&
ntohs(eh->ether_type) == ETHERTYPE_IP)
hlen = ip->ip_hl << 2;
@@ -1182,12 +1192,12 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie,
#undef PULLUP_TO
}
}
- last_pkt.src_ip = ntohl(src_ip.s_addr);
- last_pkt.dst_ip = ntohl(dst_ip.s_addr);
- last_pkt.proto = proto;
- last_pkt.src_port = ntohs(src_port);
- last_pkt.dst_port = ntohs(dst_port);
- last_pkt.flags = flags;
+ args->f_id.src_ip = ntohl(src_ip.s_addr);
+ args->f_id.dst_ip = ntohl(dst_ip.s_addr);
+ args->f_id.proto = proto;
+ args->f_id.src_port = ntohs(src_port);
+ args->f_id.dst_port = ntohs(dst_port);
+ args->f_id.flags = flags;
if (*flow_id) {
/*
@@ -1305,7 +1315,7 @@ again:
if (f->fw_flg & (IP_FW_F_KEEP_S|IP_FW_F_CHECK_S) &&
dyn_checked == 0 ) {
dyn_checked = 1 ;
- q = lookup_dyn_rule(&last_pkt, &direction);
+ q = lookup_dyn_rule(&args->f_id, &direction);
if (q != NULL) {
DEB(printf("-- dynamic match 0x%08x %d %s 0x%08x %d\n",
(q->id.src_ip), (q->id.src_port),
@@ -1539,7 +1549,7 @@ got_match:
* a new dynamic entry.
*/
if (q == NULL && f->fw_flg & IP_FW_F_KEEP_S) {
- if (install_state(f)) /* error or limit violation */
+ if (install_state(f, args)) /* error or limit violation */
goto dropit;
}
/* Update statistics */
@@ -1577,7 +1587,7 @@ got_match:
case IP_FW_F_QUEUE:
*flow_id = f; /* XXX set flow id */
return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG);
-#ifdef IPFIREWALL_FORWARD
+
case IP_FW_F_FWD:
/* Change the next-hop address for this packet.
* Initially we'll only worry about directly
@@ -1596,7 +1606,7 @@ got_match:
&& (q == NULL || direction == MATCH_FORWARD) )
*next_hop = &(f->fw_fwd_ip);
return(0); /* Allow the packet */
-#endif
+
}
/* Deny/reject this packet using this rule */
@@ -1970,9 +1980,7 @@ check_ipfw_struct(struct ip_fw *frwl)
case IP_FW_F_ACCEPT:
case IP_FW_F_COUNT:
case IP_FW_F_SKIPTO:
-#ifdef IPFIREWALL_FORWARD
case IP_FW_F_FWD:
-#endif
break;
default:
dprintf(("%s invalid command\n", err_prefix));
@@ -2179,11 +2187,7 @@ ip_fw_init(void)
#else
"divert disabled, "
#endif
-#ifdef IPFIREWALL_FORWARD
"rule-based forwarding enabled, "
-#else
- "rule-based forwarding disabled, "
-#endif
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
"default to accept, ");
#else
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index e3ffe20..dcb3bcf 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -319,6 +319,27 @@ struct ipfw_dyn_rule {
#define IP_FW_PORT_DENY_FLAG 0x40000
/*
+ * arguments for calling ip_fw_chk() and dummynet_io(). We put them
+ * all into a structure because this way it is easier and more
+ * efficient to pass variables around and extend the interface.
+ */
+struct ip_fw_args {
+ struct mbuf *m; /* the mbuf chain */
+ struct ifnet *oif; /* output interface */
+ struct sockaddr_in *next_hop; /* forward address */
+ struct ip_fw *rule; /* matching rule */
+ struct ether_header *eh; /* for bridged packets */
+
+ struct route *ro; /* for dummynet */
+ struct sockaddr_in *dst; /* for dummynet */
+ int flags; /* for dummynet */
+
+ struct ipfw_flow_id f_id; /* grabbed from IP header */
+ u_int16_t divert_rule; /* divert cookie */
+ u_int32_t retval;
+};
+
+/*
* Function definitions.
*/
void ip_fw_init(void);
@@ -326,14 +347,12 @@ void ip_fw_init(void);
/* Firewall hooks */
struct ip;
struct sockopt;
-typedef int ip_fw_chk_t (struct mbuf **m, struct ifnet *oif,
- u_int16_t *cookie, struct ip_fw **rule, struct sockaddr_in **next_hop);
+typedef int ip_fw_chk_t (struct ip_fw_args *args);
typedef int ip_fw_ctl_t (struct sockopt *);
extern ip_fw_chk_t *ip_fw_chk_ptr;
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
extern int fw_one_pass;
extern int fw_enable;
-extern struct ipfw_flow_id last_pkt;
#define IPFW_LOADED (ip_fw_chk_ptr != NULL)
#endif /* _KERNEL */
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index b7c5ea3..1d29d54 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -207,17 +207,14 @@ static struct ip_srcrt {
struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
} ip_srcrt;
-struct sockaddr_in *ip_fw_fwd_addr;
-
static void save_rte(u_char *, struct in_addr);
-static int ip_dooptions(struct mbuf *, int);
-static void ip_forward(struct mbuf *, int);
+static int ip_dooptions(struct mbuf *m, int,
+ struct sockaddr_in *next_hop);
+static void ip_forward(struct mbuf *m, int srcrt,
+ struct sockaddr_in *next_hop);
static void ip_freef(struct ipqhead *, struct ipq *);
-#ifdef IPDIVERT
-static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *, u_int32_t *, u_int16_t *);
-#else
-static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *);
-#endif
+static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *,
+ struct ipq *, u_int32_t *, u_int16_t *);
static void ipintr(void);
/*
@@ -275,43 +272,52 @@ ip_input(struct mbuf *m)
struct ifaddr *ifa;
int i, hlen, checkif;
u_short sum;
- u_int16_t divert_cookie; /* firewall cookie */
struct in_addr pkt_dst;
-#ifdef IPDIVERT
u_int32_t divert_info = 0; /* packet divert/tee info */
-#endif
- struct ip_fw *rule = NULL;
+ struct ip_fw_args args;
#ifdef PFIL_HOOKS
struct packet_filter_hook *pfh;
struct mbuf *m0;
int rv;
#endif /* PFIL_HOOKS */
-#ifdef IPDIVERT
- /* Get and reset firewall cookie */
- divert_cookie = ip_divert_cookie;
- ip_divert_cookie = 0;
-#else
- divert_cookie = 0;
-#endif
+ args.eh = NULL;
+ args.oif = NULL;
+ args.rule = NULL;
+ args.divert_rule = 0; /* divert cookie */
+ args.next_hop = NULL;
- /*
- * dummynet packet are prepended a vestigial mbuf with
- * m_type = MT_DUMMYNET and m_data pointing to the matching
- * rule.
- */
- if (m->m_type == MT_DUMMYNET) {
- rule = (struct ip_fw *)(m->m_data) ;
- m = m->m_next ;
- ip = mtod(m, struct ip *);
- hlen = IP_VHL_HL(ip->ip_vhl) << 2;
- goto iphack ;
- } else
- rule = NULL ;
+ /* Grab info from MT_TAG mbufs prepended to the chain. */
+ for (; m && m->m_type == MT_TAG; m = m->m_next) {
+ switch(m->m_tag_id) {
+ default:
+ printf("ip_input: unrecognised MT_TAG tag %d\n",
+ m->m_tag_id);
+ break;
+
+ case PACKET_TAG_DUMMYNET:
+ args.rule = ((struct dn_pkt *)m)->rule;
+ break;
+
+ case PACKET_TAG_DIVERT:
+ args.divert_rule = (int)m->m_hdr.mh_data & 0xffff;
+ break;
+
+ case PACKET_TAG_IPFORWARD:
+ args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
+ break;
+ }
+ }
KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0,
("ip_input: no HDR"));
+ if (args.rule) { /* dummynet already filtered us */
+ ip = mtod(m, struct ip *);
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+ goto iphack ;
+ }
+
ipstat.ips_total++;
if (m->m_pkthdr.len < sizeof(struct ip))
@@ -437,32 +443,29 @@ iphack:
#endif /* PFIL_HOOKS */
if (fw_enable && IPFW_LOADED) {
-#ifdef IPFIREWALL_FORWARD
/*
* If we've been forwarded from the output side, then
* skip the firewall a second time
*/
- if (ip_fw_fwd_addr)
+ if (args.next_hop)
goto ours;
-#endif /* IPFIREWALL_FORWARD */
- /*
- * See the comment in ip_output for the return values
- * produced by the firewall.
- */
- i = ip_fw_chk_ptr(&m, NULL /* oif */, &divert_cookie,
- &rule, &ip_fw_fwd_addr);
+
+ args.m = m;
+ i = ip_fw_chk_ptr(&args);
+ m = args.m;
+
if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
if (m)
m_freem(m);
return;
}
ip = mtod(m, struct ip *); /* just in case m changed */
- if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */
+ if (i == 0 && args.next_hop == NULL) /* common case */
goto pass;
if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
/* Send packet to the appropriate pipe */
- ip_dn_io_ptr(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule,
- 0);
+
+ ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
return;
}
#ifdef IPDIVERT
@@ -472,10 +475,8 @@ iphack:
goto ours;
}
#endif
-#ifdef IPFIREWALL_FORWARD
- if (i == 0 && ip_fw_fwd_addr != NULL)
+ if (i == 0 && args.next_hop != NULL)
goto pass;
-#endif
/*
* if we get here, the packet must be dropped
*/
@@ -491,12 +492,8 @@ pass:
* to be sent and the original packet to be freed).
*/
ip_nhops = 0; /* for source routed packets */
- if (hlen > sizeof (struct ip) && ip_dooptions(m, 0)) {
-#ifdef IPFIREWALL_FORWARD
- ip_fw_fwd_addr = NULL;
-#endif
+ if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop))
return;
- }
/* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
* matter if it is destined to another node, or whether it is
@@ -521,8 +518,7 @@ pass:
* Cache the destination address of the packet; this may be
* changed by use of 'ipfw fwd'.
*/
- pkt_dst = ip_fw_fwd_addr == NULL ?
- ip->ip_dst : ip_fw_fwd_addr->sin_addr;
+ pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
/*
* Enable a consistency check between the destination address
@@ -541,7 +537,7 @@ pass:
checkif = ip_checkinterface && (ipforwarding == 0) &&
m->m_pkthdr.rcvif != NULL &&
((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
- (ip_fw_fwd_addr == NULL);
+ (args.next_hop == NULL);
/*
* Check for exact addresses in the hash bucket.
@@ -651,11 +647,8 @@ pass:
goto bad;
}
#endif /* IPSEC */
- ip_forward(m, 0);
+ ip_forward(m, 0, args.next_hop);
}
-#ifdef IPFIREWALL_FORWARD
- ip_fw_fwd_addr = NULL;
-#endif
return;
ours:
@@ -664,12 +657,9 @@ ours:
* IPSTEALTH: Process non-routing options only
* if the packet is destined for us.
*/
- if (ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1)) {
-#ifdef IPFIREWALL_FORWARD
- ip_fw_fwd_addr = NULL;
-#endif
+ if (ipstealth && hlen > sizeof (struct ip) &&
+ ip_dooptions(m, 1, args.next_hop))
return;
- }
#endif /* IPSTEALTH */
/* Count the packet in the ip address stats */
@@ -740,21 +730,15 @@ found:
/*
* Attempt reassembly; if it succeeds, proceed.
+ * ip_reass() will return a different mbuf, and update
+ * the divert info in divert_info and args.divert_rule.
*/
ipstat.ips_fragments++;
m->m_pkthdr.header = ip;
-#ifdef IPDIVERT
m = ip_reass(m,
- &ipq[sum], fp, &divert_info, &divert_cookie);
-#else
- m = ip_reass(m, &ipq[sum], fp);
-#endif
- if (m == 0) {
-#ifdef IPFIREWALL_FORWARD
- ip_fw_fwd_addr = NULL;
-#endif
+ &ipq[sum], fp, &divert_info, &args.divert_rule);
+ if (m == 0)
return;
- }
ipstat.ips_reassembled++;
ip = mtod(m, struct ip *);
/* Get the header length of the reassembled packet */
@@ -781,9 +765,6 @@ found:
#ifdef IPDIVERT
/*
* Divert or tee packet to the divert protocol if required.
- *
- * If divert_info is zero then cookie should be too, so we shouldn't
- * need to clear them here. Assume divert_packet() does so also.
*/
if (divert_info != 0) {
struct mbuf *clone = NULL;
@@ -798,8 +779,7 @@ found:
ip->ip_off = htons(ip->ip_off);
/* Deliver packet to divert input routine */
- ip_divert_cookie = divert_cookie;
- divert_packet(m, 1, divert_info & 0xffff);
+ divert_packet(m, 1, divert_info & 0xffff, args.divert_rule);
ipstat.ips_delivered++;
/* If 'tee', continue with original packet */
@@ -808,6 +788,13 @@ found:
m = clone;
ip = mtod(m, struct ip *);
ip->ip_len += hlen;
+ /*
+ * Jump backwards to complete processing of the
+ * packet. But first clear divert_info to avoid
+ * entering this block again.
+ * We do not need to clear args.divert_rule
+ * or args.next_hop as they will not be used.
+ */
divert_info = 0;
goto pass;
}
@@ -830,19 +817,21 @@ found:
* Switch out to protocol's input routine.
*/
ipstat.ips_delivered++;
- {
- int off = hlen;
+ if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
+ /* TCP needs IPFORWARD info if available */
+ struct m_hdr tag;
- (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off);
-#ifdef IPFIREWALL_FORWARD
- ip_fw_fwd_addr = NULL; /* tcp needed it */
-#endif
+ tag.mh_type = MT_TAG;
+ tag.mh_flags = PACKET_TAG_IPFORWARD;
+ tag.mh_data = (caddr_t)args.next_hop;
+ tag.mh_next = m;
+
+ (*inetsw[ip_protox[ip->ip_p]].pr_input)(
+ (struct mbuf *)&tag, hlen);
+ } else
+ (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
return;
- }
bad:
-#ifdef IPFIREWALL_FORWARD
- ip_fw_fwd_addr = NULL;
-#endif
m_freem(m);
}
@@ -869,21 +858,13 @@ ipintr(void)
*
* When IPDIVERT enabled, keep additional state with each packet that
* tells us if we need to divert or tee the packet we're building.
+ * In particular, *divinfo includes the port and TEE flag,
+ * *divert_rule is the number of the matching rule.
*/
static struct mbuf *
-#ifdef IPDIVERT
-ip_reass(m, head, fp, divinfo, divcookie)
-#else
-ip_reass(m, head, fp)
-#endif
- struct mbuf *m;
- struct ipqhead *head;
- struct ipq *fp;
-#ifdef IPDIVERT
- u_int32_t *divinfo;
- u_int16_t *divcookie;
-#endif
+ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp,
+ u_int32_t *divinfo, u_int16_t *divert_rule)
{
struct ip *ip = mtod(m, struct ip *);
register struct mbuf *p, *q, *nq;
@@ -990,12 +971,14 @@ inserted:
#ifdef IPDIVERT
/*
* Transfer firewall instructions to the fragment structure.
- * Any fragment diverting causes the whole packet to divert.
+ * Only trust info in the fragment at offset 0.
*/
- fp->ipq_div_info = *divinfo;
- fp->ipq_div_cookie = *divcookie;
+ if (ip->ip_off == 0) {
+ fp->ipq_div_info = *divinfo;
+ fp->ipq_div_cookie = *divert_rule;
+ }
*divinfo = 0;
- *divcookie = 0;
+ *divert_rule = 0;
#endif
/*
@@ -1044,7 +1027,7 @@ inserted:
* Extract firewall instructions from the fragment structure.
*/
*divinfo = fp->ipq_div_info;
- *divcookie = fp->ipq_div_cookie;
+ *divert_rule = fp->ipq_div_cookie;
#endif
/*
@@ -1074,7 +1057,7 @@ inserted:
dropfrag:
#ifdef IPDIVERT
*divinfo = 0;
- *divcookie = 0;
+ *divert_rule = 0;
#endif
ipstat.ips_fragdropped++;
m_freem(m);
@@ -1177,13 +1160,11 @@ ip_drain()
* 0 if the packet should be processed further.
*/
static int
-ip_dooptions(m, pass)
- struct mbuf *m;
- int pass;
+ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
{
- register struct ip *ip = mtod(m, struct ip *);
- register u_char *cp;
- register struct in_ifaddr *ia;
+ 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;
@@ -1427,7 +1408,7 @@ dropit:
}
}
if (forward && ipforwarding) {
- ip_forward(m, 1);
+ ip_forward(m, 1, next_hop);
return (1);
}
return (0);
@@ -1611,12 +1592,10 @@ u_char inetctlerrmap[PRC_NCMDS] = {
* via a source route.
*/
static void
-ip_forward(m, srcrt)
- struct mbuf *m;
- int srcrt;
+ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
{
- register struct ip *ip = mtod(m, struct ip *);
- register struct rtentry *rt;
+ struct ip *ip = mtod(m, struct ip *);
+ struct rtentry *rt;
int error, type = 0, code = 0;
struct mbuf *mcopy;
n_long dest;
@@ -1631,8 +1610,7 @@ ip_forward(m, srcrt)
* Cache the destination address of the packet; this may be
* changed by use of 'ipfw fwd'.
*/
- pkt_dst = ip_fw_fwd_addr == NULL ?
- ip->ip_dst : ip_fw_fwd_addr->sin_addr;
+ pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst;
#ifdef DIAGNOSTIC
if (ipprintfs)
@@ -1701,7 +1679,7 @@ ip_forward(m, srcrt)
if (rt->rt_ifp == m->m_pkthdr.rcvif &&
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
- ipsendredirects && !srcrt && !ip_fw_fwd_addr) {
+ ipsendredirects && !srcrt && !next_hop) {
#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
u_long src = ntohl(ip->ip_src.s_addr);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index f553872..1b0cd61 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -80,12 +80,11 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
-#ifdef IPFIREWALL_FORWARD_DEBUG
-#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\
- (ntohl(a.s_addr)>>16)&0xFF,\
- (ntohl(a.s_addr)>>8)&0xFF,\
- (ntohl(a.s_addr))&0xFF);
-#endif
+#define print_ip(x, a, y) printf("%s %d.%d.%d.%d%s",\
+ x, (ntohl(a.s_addr)>>24)&0xFF,\
+ (ntohl(a.s_addr)>>16)&0xFF,\
+ (ntohl(a.s_addr)>>8)&0xFF,\
+ (ntohl(a.s_addr))&0xFF, y);
u_short ip_id;
@@ -119,11 +118,11 @@ ip_output(m0, opt, ro, flags, imo)
struct ip_moptions *imo;
{
struct ip *ip, *mhip;
- struct ifnet *ifp;
- struct mbuf *m = m0;
+ struct ifnet *ifp = NULL; /* keep compiler happy */
+ struct mbuf *m;
int hlen = sizeof (struct ip);
int len, off, error = 0;
- struct sockaddr_in *dst;
+ struct sockaddr_in *dst = NULL; /* keep compiler happy */
struct in_ifaddr *ia;
int isbroadcast, sw_csum;
struct in_addr pkt_dst;
@@ -132,72 +131,75 @@ ip_output(m0, opt, ro, flags, imo)
struct socket *so = NULL;
struct secpolicy *sp = NULL;
#endif
- u_int16_t divert_cookie; /* firewall cookie */
+ struct ip_fw_args args;
+ int src_was_INADDR_ANY = 0; /* as the name says... */
#ifdef PFIL_HOOKS
struct packet_filter_hook *pfh;
struct mbuf *m1;
int rv;
#endif /* PFIL_HOOKS */
-#ifdef IPFIREWALL_FORWARD
- int fwd_rewrite_src = 0;
-#endif
- struct ip_fw *rule = NULL;
-
-#ifdef IPDIVERT
- /* Get and reset firewall cookie */
- divert_cookie = ip_divert_cookie;
- ip_divert_cookie = 0;
-#else
- divert_cookie = 0;
-#endif
- /*
- * dummynet packet are prepended a vestigial mbuf with
- * m_type = MT_DUMMYNET and m_data pointing to the matching
- * rule.
- */
- if (m->m_type == MT_DUMMYNET) {
- /*
- * the packet was already tagged, so part of the
- * processing was already done, and we need to go down.
- * Get parameters from the header.
- */
- rule = (struct ip_fw *)(m->m_data) ;
- opt = NULL ;
- ro = & ( ((struct dn_pkt *)m)->ro ) ;
- imo = NULL ;
- dst = ((struct dn_pkt *)m)->dn_dst ;
- ifp = ((struct dn_pkt *)m)->ifp ;
- flags = ((struct dn_pkt *)m)->flags ;
-
- m0 = m = m->m_next ;
-#ifdef IPSEC
- so = ipsec_getsocket(m);
- (void)ipsec_setsocket(m, NULL);
-#endif
- ip = mtod(m, struct ip *);
- hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
- ia = ifatoia(ro->ro_rt->rt_ifa);
- goto sendit;
- } else
- rule = NULL ;
-#ifdef IPSEC
- so = ipsec_getsocket(m);
- (void)ipsec_setsocket(m, NULL);
-#endif
+ args.eh = NULL;
+ args.rule = NULL;
+ args.next_hop = NULL;
+ args.divert_rule = 0; /* divert cookie */
+
+ /* Grab info from MT_TAG mbufs prepended to the chain. */
+ for (; m0 && m0->m_type == MT_TAG; m0 = m0->m_next) {
+ switch(m0->m_tag_id) {
+ default:
+ printf("ip_output: unrecognised MT_TAG tag %d\n",
+ m0->m_tag_id);
+ break;
+
+ case PACKET_TAG_DUMMYNET:
+ /*
+ * the packet was already tagged, so part of the
+ * processing was already done, and we need to go down.
+ * Get parameters from the header.
+ */
+ args.rule = ((struct dn_pkt *)m0)->rule;
+ opt = NULL ;
+ ro = & ( ((struct dn_pkt *)m0)->ro ) ;
+ imo = NULL ;
+ dst = ((struct dn_pkt *)m0)->dn_dst ;
+ ifp = ((struct dn_pkt *)m0)->ifp ;
+ flags = ((struct dn_pkt *)m0)->flags ;
+ break;
+
+ case PACKET_TAG_DIVERT:
+ args.divert_rule = (int)m0->m_data & 0xffff;
+ break;
+
+ case PACKET_TAG_IPFORWARD:
+ args.next_hop = (struct sockaddr_in *)m0->m_data;
+ break;
+ }
+ }
+ m = m0;
- KASSERT((m->m_flags & M_PKTHDR) != 0, ("ip_output: no HDR"));
+ KASSERT(!m || (m->m_flags & M_PKTHDR) != 0, ("ip_output: no HDR"));
KASSERT(ro != NULL, ("ip_output: no route, proto %d",
mtod(m, struct ip *)->ip_p));
+#ifdef IPSEC
+ so = ipsec_getsocket(m);
+ (void)ipsec_setsocket(m, NULL);
+#endif
+ if (args.rule != NULL) { /* dummynet already saw us */
+ ip = mtod(m, struct ip *);
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2 ;
+ ia = ifatoia(ro->ro_rt->rt_ifa);
+ goto sendit;
+ }
+
if (opt) {
m = ip_insertoptions(m, opt, &len);
hlen = len;
}
ip = mtod(m, struct ip *);
- pkt_dst = ip_fw_fwd_addr == NULL
- ? ip->ip_dst : ip_fw_fwd_addr->sin_addr;
+ pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
/*
* Fill in IP header.
@@ -393,21 +395,16 @@ ip_output(m0, opt, ro, flags, imo)
}
#ifndef notdef
/*
- * If source address not specified yet, use address
- * of outgoing interface.
+ * If the source address is not specified yet, use the address
+ * of the outoing interface. In case, keep note we did that, so
+ * if the the firewall changes the next-hop causing the output
+ * interface to change, we can fix that.
*/
if (ip->ip_src.s_addr == INADDR_ANY) {
/* Interface may have no addresses. */
if (ia != NULL) {
ip->ip_src = IA_SIN(ia)->sin_addr;
-#ifdef IPFIREWALL_FORWARD
- /* Keep note that we did this - if the firewall changes
- * the next-hop, our interface may change, changing the
- * default source IP. It's a shame so much effort happens
- * twice. Oh well.
- */
- fwd_rewrite_src++;
-#endif /* IPFIREWALL_FORWARD */
+ src_was_INADDR_ANY = 1;
}
}
#endif /* notdef */
@@ -605,10 +602,16 @@ skip_ipsec:
* Check with the firewall...
* but not if we are already being fwd'd from a firewall.
*/
- if (fw_enable && IPFW_LOADED && !ip_fw_fwd_addr) {
+ if (fw_enable && IPFW_LOADED && !args.next_hop) {
struct sockaddr_in *old = dst;
- off = ip_fw_chk_ptr(&m, ifp, &divert_cookie, &rule, &dst);
+ args.m = m;
+ args.next_hop = dst;
+ args.oif = ifp;
+ off = ip_fw_chk_ptr(&args);
+ m = args.m;
+ dst = args.next_hop;
+
/*
* On return we must do the following:
* m == NULL -> drop the pkt (old interface, deprecated)
@@ -643,8 +646,12 @@ skip_ipsec:
* XXX note: if the ifp or ro entry are deleted
* while a pkt is in dummynet, we are in trouble!
*/
- error = ip_dn_io_ptr(off & 0xffff, DN_TO_IP_OUT, m,
- ifp, ro, dst, rule, flags);
+ args.ro = ro;
+ args.dst = dst;
+ args.flags = flags;
+
+ error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP_OUT,
+ &args);
goto done;
}
#ifdef IPDIVERT
@@ -670,8 +677,7 @@ skip_ipsec:
ip->ip_off = htons(ip->ip_off);
/* Deliver packet to divert input routine */
- ip_divert_cookie = divert_cookie;
- divert_packet(m, 0, off & 0xffff);
+ divert_packet(m, 0, off & 0xffff, args.divert_rule);
/* If 'tee', continue with original packet */
if (clone != NULL) {
@@ -683,8 +689,9 @@ skip_ipsec:
}
#endif
-#ifdef IPFIREWALL_FORWARD
- /* Here we check dst to make sure it's directly reachable on the
+ /* IPFIREWALL_FORWARD */
+ /*
+ * Check dst to make sure it is directly reachable on the
* interface we previously thought it was.
* If it isn't (which may be likely in some situations) we have
* to re-route it (ie, find a route for the next-hop and the
@@ -693,20 +700,39 @@ skip_ipsec:
* such control is nigh impossible. So we do it here.
* And I'm babbling.
*/
- if (off == 0 && old != dst) {
+ if (off == 0 && old != dst) { /* FORWARD, dst has changed */
+#if 0
+ /*
+ * XXX To improve readability, this block should be
+ * changed into a function call as below:
+ */
+ error = ip_ipforward(&m, &dst, &ifp);
+ if (error)
+ goto bad;
+ if (m == NULL) /* ip_input consumed the mbuf */
+ goto done;
+#else
struct in_ifaddr *ia;
- /* It's changed... */
+ /*
+ * XXX sro_fwd below is static, and a pointer
+ * to it gets passed to routines downstream.
+ * This could have surprisingly bad results in
+ * practice, because its content is overwritten
+ * by subsequent packets.
+ */
/* There must be a better way to do this next line... */
- static struct route sro_fwd, *ro_fwd = &sro_fwd;
-#ifdef IPFIREWALL_FORWARD_DEBUG
- printf("IPFIREWALL_FORWARD: New dst ip: ");
- print_ip(dst->sin_addr);
- printf("\n");
+ static struct route sro_fwd;
+ struct route *ro_fwd = &sro_fwd;
+
+#if 0
+ print_ip("IPFIREWALL_FORWARD: New dst ip: ",
+ dst->sin_addr, "\n");
#endif
+
/*
* We need to figure out if we have been forwarded
- * to a local socket. If so then we should somehow
+ * to a local socket. If so, then we should somehow
* "loop back" to ip_input, and get directed to the
* PCB as if we had received this packet. This is
* because it may be dificult to identify the packets
@@ -728,9 +754,14 @@ skip_ipsec:
dst->sin_addr.s_addr)
break;
}
- if (ia) {
- /* tell ip_input "dont filter" */
- ip_fw_fwd_addr = dst;
+ if (ia) { /* tell ip_input "dont filter" */
+ struct m_hdr tag;
+
+ tag.mh_type = MT_TAG;
+ tag.mh_flags = PACKET_TAG_IPFORWARD;
+ tag.mh_data = (caddr_t)args.next_hop;
+ tag.mh_next = m;
+
if (m->m_pkthdr.rcvif == NULL)
m->m_pkthdr.rcvif = ifunit("lo0");
if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
@@ -742,7 +773,7 @@ skip_ipsec:
CSUM_IP_CHECKED | CSUM_IP_VALID;
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
- ip_input(m);
+ ip_input((struct mbuf *)&tag);
goto done;
}
/* Some of the logic for this was
@@ -766,7 +797,8 @@ skip_ipsec:
ifp = ro_fwd->ro_rt->rt_ifp;
ro_fwd->ro_rt->rt_use++;
if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
- dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
+ dst = (struct sockaddr_in *)
+ ro_fwd->ro_rt->rt_gateway;
if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
isbroadcast =
(ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
@@ -777,16 +809,17 @@ skip_ipsec:
ro->ro_rt = ro_fwd->ro_rt;
dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
+#endif /* ... block to be put into a function */
/*
* If we added a default src ip earlier,
* which would have been gotten from the-then
* interface, do it again, from the new one.
*/
- if (fwd_rewrite_src)
+ if (src_was_INADDR_ANY)
ip->ip_src = IA_SIN(ia)->sin_addr;
goto pass ;
}
-#endif /* IPFIREWALL_FORWARD */
+
/*
* if we get here, none of the above matches, and
* we have to drop the pkt
@@ -796,7 +829,6 @@ skip_ipsec:
goto done;
}
- ip_fw_fwd_addr = NULL;
pass:
/* 127/8 must not appear on wire - RFC1122. */
if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index dad22f3..4a580a6 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -192,9 +192,8 @@ void ip_rsvp_force_done(struct socket *);
#ifdef IPDIVERT
void div_init(void);
void div_input(struct mbuf *, int);
-void divert_packet(struct mbuf *, int, int);
+void divert_packet(struct mbuf *m, int incoming, int port, int rule);
extern struct pr_usrreqs div_usrreqs;
-extern u_int16_t ip_divert_cookie;
#endif
extern struct sockaddr_in *ip_fw_fwd_addr;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 95d21ce..25db5c1 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -358,8 +358,15 @@ tcp_input(m, off0)
struct ip6_hdr *ip6 = NULL;
int isipv6;
#endif /* INET6 */
+ struct sockaddr_in *next_hop = NULL;
int rstreason; /* For badport_bandlim accounting purposes */
+ /* Grab info from MT_TAG mbufs prepended to the chain. */
+ for (;m && m->m_type == MT_TAG; m = m->m_next) {
+ if (m->m_tag_id == PACKET_TAG_IPFORWARD)
+ next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
+ }
+
#ifdef INET6
isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
#endif
@@ -512,14 +519,14 @@ tcp_input(m, off0)
INP_INFO_WLOCK(&tcbinfo);
headlocked = 1;
findpcb:
-#ifdef IPFIREWALL_FORWARD
- if (ip_fw_fwd_addr != NULL
+ /* IPFIREWALL_FORWARD section */
+ if (next_hop != NULL
#ifdef INET6
&& isipv6 == NULL /* IPv6 support is not yet */
#endif /* INET6 */
) {
/*
- * Diverted. Pretend to be the destination.
+ * Transparently forwarded. Pretend to be the destination.
* already got one like this?
*/
inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
@@ -528,21 +535,19 @@ findpcb:
/*
* No, then it's new. Try find the ambushing socket
*/
- if (!ip_fw_fwd_addr->sin_port) {
+ if (next_hop->sin_port == 0) {
inp = in_pcblookup_hash(&tcbinfo, ip->ip_src,
- th->th_sport, ip_fw_fwd_addr->sin_addr,
+ th->th_sport, next_hop->sin_addr,
th->th_dport, 1, m->m_pkthdr.rcvif);
} else {
inp = in_pcblookup_hash(&tcbinfo,
ip->ip_src, th->th_sport,
- ip_fw_fwd_addr->sin_addr,
- ntohs(ip_fw_fwd_addr->sin_port), 1,
+ next_hop->sin_addr,
+ ntohs(next_hop->sin_port), 1,
m->m_pkthdr.rcvif);
}
}
- ip_fw_fwd_addr = NULL;
} else
-#endif /* IPFIREWALL_FORWARD */
{
#ifdef INET6
if (isipv6)
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 95d21ce..25db5c1 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -358,8 +358,15 @@ tcp_input(m, off0)
struct ip6_hdr *ip6 = NULL;
int isipv6;
#endif /* INET6 */
+ struct sockaddr_in *next_hop = NULL;
int rstreason; /* For badport_bandlim accounting purposes */
+ /* Grab info from MT_TAG mbufs prepended to the chain. */
+ for (;m && m->m_type == MT_TAG; m = m->m_next) {
+ if (m->m_tag_id == PACKET_TAG_IPFORWARD)
+ next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
+ }
+
#ifdef INET6
isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
#endif
@@ -512,14 +519,14 @@ tcp_input(m, off0)
INP_INFO_WLOCK(&tcbinfo);
headlocked = 1;
findpcb:
-#ifdef IPFIREWALL_FORWARD
- if (ip_fw_fwd_addr != NULL
+ /* IPFIREWALL_FORWARD section */
+ if (next_hop != NULL
#ifdef INET6
&& isipv6 == NULL /* IPv6 support is not yet */
#endif /* INET6 */
) {
/*
- * Diverted. Pretend to be the destination.
+ * Transparently forwarded. Pretend to be the destination.
* already got one like this?
*/
inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
@@ -528,21 +535,19 @@ findpcb:
/*
* No, then it's new. Try find the ambushing socket
*/
- if (!ip_fw_fwd_addr->sin_port) {
+ if (next_hop->sin_port == 0) {
inp = in_pcblookup_hash(&tcbinfo, ip->ip_src,
- th->th_sport, ip_fw_fwd_addr->sin_addr,
+ th->th_sport, next_hop->sin_addr,
th->th_dport, 1, m->m_pkthdr.rcvif);
} else {
inp = in_pcblookup_hash(&tcbinfo,
ip->ip_src, th->th_sport,
- ip_fw_fwd_addr->sin_addr,
- ntohs(ip_fw_fwd_addr->sin_port), 1,
+ next_hop->sin_addr,
+ ntohs(next_hop->sin_port), 1,
m->m_pkthdr.rcvif);
}
}
- ip_fw_fwd_addr = NULL;
} else
-#endif /* IPFIREWALL_FORWARD */
{
#ifdef INET6
if (isipv6)
OpenPOWER on IntegriCloud