diff options
-rw-r--r-- | sys/net/bridge.c | 87 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 67 | ||||
-rw-r--r-- | sys/netinet/ip_divert.c | 131 | ||||
-rw-r--r-- | sys/netinet/ip_dummynet.c | 85 | ||||
-rw-r--r-- | sys/netinet/ip_dummynet.h | 40 | ||||
-rw-r--r-- | sys/netinet/ip_fw.c | 80 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 25 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 224 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 218 | ||||
-rw-r--r-- | sys/netinet/ip_var.h | 3 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 23 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 23 |
12 files changed, 532 insertions, 474 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c index 48a31cc546ca..6fc888e6a487 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 16fb62fe2724..ad3db35b832b 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 d0dfd1f3333a..e58f07927caf 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 fa7fd912d4f8..6006b650df5e 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 ff482d7c9085..3453517589bb 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 016022ea0714..d7ccad7c55c3 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 e3ffe204686d..dcb3bcf783fe 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 b7c5ea3872c3..1d29d54d93a7 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 f553872e6541..1b0cd61507b3 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 dad22f3da19c..4a580a628fe4 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 95d21ce6813f..25db5c1fde5e 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 95d21ce6813f..25db5c1fde5e 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) |