summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2002-06-22 11:51:02 +0000
committerluigi <luigi@FreeBSD.org>2002-06-22 11:51:02 +0000
commit525988814841e0e419cfa1953c8a04c04afbd5dc (patch)
treef4d7bf09d236eefd4fcbab875c3c30a48941891b /sys/netinet
parentae0152f4c1645e2948481426e810382b76d0ebda (diff)
downloadFreeBSD-src-525988814841e0e419cfa1953c8a04c04afbd5dc.zip
FreeBSD-src-525988814841e0e419cfa1953c8a04c04afbd5dc.tar.gz
Remove (almost all) global variables that were used to hold
packet forwarding state ("annotations") during ip processing. The code is considerably cleaner now. The variables removed by this change are: ip_divert_cookie used by divert sockets ip_fw_fwd_addr used for transparent ip redirection last_pkt used by dynamic pipes in dummynet Removal of the first two has been done by carrying the annotations into volatile structs prepended to the mbuf chains, and adding appropriate code to add/remove annotations in the routines which make use of them, i.e. ip_input(), ip_output(), tcp_input(), bdg_forward(), ether_demux(), ether_output_frame(), div_output(). On passing, remove a bug in divert handling of fragmented packet. Now it is the fragment at offset 0 which sets the divert status of the whole packet, whereas formerly it was the last incoming fragment to decide. Removal of last_pkt required a change in the interface of ip_fw_chk() and dummynet_io(). On passing, use the same mechanism for dummynet annotations and for divert/forward annotations. option IPFIREWALL_FORWARD is effectively useless, the code to implement it is very small and is now in by default to avoid the obfuscation of conditionally compiled code. NOTES: * there is at least one global variable left, sro_fwd, in ip_output(). I am not sure if/how this can be removed. * I have deliberately avoided gratuitous style changes in this commit to avoid cluttering the diffs. Minor stule cleanup will likely be necessary * this commit only focused on the IP layer. I am sure there is a number of global variables used in the TCP and maybe UDP stack. * despite the number of files touched, there are absolutely no API's or data structures changed by this commit (except the interfaces of ip_fw_chk() and dummynet_io(), which are internal anyways), so an MFC is quite safe and unintrusive (and desirable, given the improved readability of the code). MFC after: 10 days
Diffstat (limited to 'sys/netinet')
-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
10 files changed, 442 insertions, 410 deletions
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