summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorarchie <archie@FreeBSD.org>1999-12-06 00:43:07 +0000
committerarchie <archie@FreeBSD.org>1999-12-06 00:43:07 +0000
commita35284d781617f9cc0ed2732744007cbbd5b3e75 (patch)
treeed4ccc9be688881857acbd7860fc6783bdb2a34b /sys/netinet
parente4171de86a0a3c0ac24ac0ad201e38461964474b (diff)
downloadFreeBSD-src-a35284d781617f9cc0ed2732744007cbbd5b3e75.zip
FreeBSD-src-a35284d781617f9cc0ed2732744007cbbd5b3e75.tar.gz
Miscellaneous fixes/cleanups relating to ipfw and divert(4):
- Implement 'ipfw tee' (finally) - Divert packets by calling new function divert_packet() directly instead of going through protosw[]. - Replace kludgey global variable 'ip_divert_port' with a function parameter to divert_packet() - Replace kludgey global variable 'frag_divert_port' with a function parameter to ip_reass() - style(9) fixes Reviewed by: julian, green
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_divert.c79
-rw-r--r--sys/netinet/ip_fw.c120
-rw-r--r--sys/netinet/ip_fw.h3
-rw-r--r--sys/netinet/ip_input.c173
-rw-r--r--sys/netinet/ip_output.c44
-rw-r--r--sys/netinet/ip_var.h8
6 files changed, 235 insertions, 192 deletions
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index 32a13f2..a2b76b3 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -72,31 +72,23 @@
#define DIVSNDQ (65536 + 100)
#define DIVRCVQ (65536 + 100)
-/* Global variables */
-
-/*
- * ip_input() and ip_output() set this secret value before calling us to
- * let us know which divert port to divert a packet to; this is done so
- * we can use the existing prototype for struct protosw's pr_input().
- * This is stored in host order.
- */
-u_short ip_divert_port;
-
/*
- * A 16 bit cookie is passed to the user process.
- * The user process can send it back to help the caller know something
- * about where the packet came from.
+ * 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.
*
- * If IPFW is the caller then the cookie is the rule that sent
+ * 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.
+ *
+ * For divert_packet(), ip_divert_cookie is an input value only.
+ * For div_output(), ip_divert_cookie is an output value only.
*/
u_int16_t ip_divert_cookie;
/* Internal variables */
-
static struct inpcbhead divcb;
static struct inpcbinfo divcbinfo;
@@ -107,7 +99,6 @@ static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */
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);
@@ -131,23 +122,36 @@ div_init(void)
}
/*
- * Setup generic address and protocol structures
- * for div_input routine, then pass them along with
- * mbuf chain. ip->ip_len is assumed to have had
- * the header length (hlen) subtracted out already.
- * We tell whether the packet was incoming or outgoing
- * by seeing if hlen == 0, which is a hack.
+ * IPPROTO_DIVERT is not a real IP protocol; don't allow any packets
+ * with that protocol number to enter the system from the outside.
*/
void
div_input(struct mbuf *m, int hlen)
{
+ ipstat.ips_noproto++;
+ m_freem(m);
+}
+
+/*
+ * Divert a packet by passing it up to the divert socket at port 'port'.
+ *
+ * Setup generic address and protocol structures for div_input routine,
+ * then pass them along with mbuf chain.
+ */
+void
+divert_packet(struct mbuf *m, int incoming, int port)
+{
struct ip *ip;
struct inpcb *inp;
struct socket *sa;
+ u_int16_t nport;
/* Sanity check */
- if (ip_divert_port == 0)
- panic("div_input: port is 0");
+ KASSERT(port != 0, ("%s: port=0", __FUNCTION__));
+
+ /* Record and reset divert cookie */
+ divsrc.sin_port = ip_divert_cookie;
+ ip_divert_cookie = 0;
/* Assure header */
if (m->m_len < sizeof(struct ip) &&
@@ -156,31 +160,16 @@ div_input(struct mbuf *m, int hlen)
}
ip = mtod(m, struct ip *);
- /* Record divert cookie */
- divsrc.sin_port = ip_divert_cookie;
- ip_divert_cookie = 0;
-
- /* Restore packet header fields */
- ip->ip_len += hlen;
- HTONS(ip->ip_len);
- HTONS(ip->ip_off);
-
/*
- * Record receive interface address, if any
+ * Record receive interface address, if any.
* But only for incoming packets.
*/
divsrc.sin_addr.s_addr = 0;
- if (hlen) {
+ if (incoming) {
struct ifaddr *ifa;
-#ifdef DIAGNOSTIC
/* Sanity check */
- if (!(m->m_flags & M_PKTHDR))
- panic("div_input: no pkt hdr");
-#endif
-
- /* More fields affected by ip_input() */
- HTONS(ip->ip_id);
+ KASSERT((m->m_flags & M_PKTHDR), ("%s: !PKTHDR", __FUNCTION__));
/* Find IP address for receive interface */
for (ifa = m->m_pkthdr.rcvif->if_addrhead.tqh_first;
@@ -224,11 +213,11 @@ div_input(struct mbuf *m, int hlen)
/* Put packet on socket queue, if any */
sa = NULL;
+ nport = htons((u_int16_t)port);
for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
- if (inp->inp_lport == htons(ip_divert_port))
+ if (inp->inp_lport == nport)
sa = inp->inp_socket;
}
- ip_divert_port = 0;
if (sa) {
if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc,
m, (struct mbuf *)0) == 0)
@@ -338,8 +327,8 @@ div_output(so, m, addr, control)
return error;
cantsend:
- ip_divert_cookie = 0;
m_freem(m);
+ ip_divert_cookie = 0;
return error;
}
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index 46c7d54..a70822e 100644
--- a/sys/netinet/ip_fw.c
+++ b/sys/netinet/ip_fw.c
@@ -478,6 +478,7 @@ lookup_next_rule(struct ip_fw_chain *me)
* hlen Packet header length
* oif Outgoing interface, or NULL if packet is incoming
* *cookie Skip up to the first rule past this rule number;
+ * upon return, non-zero port number for divert or tee
* *m The packet; we set to NULL when/if we nuke it.
* *flow_id pointer to the last matching rule (in/out)
* *next_hop socket we are forwarding to (in/out).
@@ -487,7 +488,13 @@ lookup_next_rule(struct ip_fw_chain *me)
* 0 The packet is to be accepted and routed normally OR
* the packet was denied/rejected and has been dropped;
* in the latter case, *m is equal to NULL upon return.
- * port Divert the packet to port.
+ * port Divert the packet to port, with these caveats:
+ *
+ * - If IP_FW_PORT_TEE_FLAG is set, tee the packet instead
+ * of diverting it (ie, 'ipfw tee').
+ *
+ * - If IP_FW_PORT_DYNT_FLAG is set, interpret the lower
+ * 16 bits as a dummynet pipe number instead of diverting
*/
static int
@@ -502,7 +509,11 @@ ip_fw_chk(struct ip **pip, int hlen,
struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
u_short offset = 0 ;
u_short src_port, dst_port;
- u_int16_t skipto = *cookie;
+ u_int16_t skipto;
+
+ /* Grab and reset cookie */
+ skipto = *cookie;
+ *cookie = 0;
if (pip) { /* normal ip packet */
ip = *pip;
@@ -532,34 +543,37 @@ non_ip: ip = NULL ;
}
if (*flow_id) {
- if (fw_one_pass)
- return 0 ; /* accept if passed first test */
- /*
- * pkt has already been tagged. Look for the next rule
- * to restart processing
- */
- chain = LIST_NEXT( *flow_id, chain);
-
- if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL )
- chain = (*flow_id)->rule->next_rule_ptr =
- lookup_next_rule(*flow_id) ;
- if (! chain) goto dropit;
- } else {
- /*
- * Go down the chain, looking for enlightment
- * If we've been asked to start at a given rule immediatly, do so.
- */
- chain = LIST_FIRST(&ip_fw_chain);
- if ( skipto ) {
- if (skipto >= IPFW_DEFAULT_RULE)
+
+ /* Accept if passed first test */
+ if (fw_one_pass)
+ return 0;
+
+ /*
+ * Packet has already been tagged. Look for the next rule
+ * to restart processing.
+ */
+ chain = LIST_NEXT(*flow_id, chain);
+
+ if ((chain = (*flow_id)->rule->next_rule_ptr) == NULL)
+ chain = (*flow_id)->rule->next_rule_ptr =
+ lookup_next_rule(*flow_id);
+ if (chain == NULL)
goto dropit;
- while (chain && (chain->rule->fw_number <= skipto)) {
- chain = LIST_NEXT(chain, chain);
+ } else {
+ /*
+ * Go down the chain, looking for enlightment.
+ * If we've been asked to start at a given rule, do so
+ */
+ chain = LIST_FIRST(&ip_fw_chain);
+ if (skipto != 0) {
+ if (skipto >= IPFW_DEFAULT_RULE)
+ goto dropit;
+ while (chain && chain->rule->fw_number <= skipto)
+ chain = LIST_NEXT(chain, chain);
+ if (chain == NULL)
+ goto dropit;
}
- if (! chain) goto dropit;
- }
}
- *cookie = 0;
for (; chain; chain = LIST_NEXT(chain, chain)) {
register struct ip_fw * f ;
again:
@@ -661,8 +675,8 @@ again:
* here, pip==NULL for bridged pkts -- they include the ethernet
* header so i have to adjust lengths accordingly
*/
-#define PULLUP_TO(l) do { \
- int len = (pip ? l : l + 14 ) ; \
+#define PULLUP_TO(l) do { \
+ int len = (pip ? (l) : (l) + 14 ); \
if ((*m)->m_len < (len) ) { \
if ( (*m = m_pullup(*m, (len))) == 0) \
goto bogusfrag; \
@@ -706,8 +720,8 @@ again:
} else if (!groupmember(f->fw_gid,
P->inp_socket->so_cred))
continue;
- } else continue;
-
+ } else
+ continue;
break;
}
@@ -737,24 +751,14 @@ again:
} else if (!groupmember(f->fw_gid,
P->inp_socket->so_cred))
continue;
- } else continue;
-
+ } else
+ continue;
break;
}
- default:
- continue;
-/*
- * XXX Shouldn't GCC be allowing two bogusfrag labels if they're both inside
- * separate blocks? Hmm.... It seems it's got incorrect behavior here.
- */
-#if 0
-bogusfrag:
- if (fw_verbose)
- ipfw_report(NULL, ip, rif, oif);
- goto dropit;
-#endif
- }
+ default:
+ continue;
+ }
}
/* Protocol specific checks */
@@ -831,10 +835,14 @@ check_ports:
}
#undef PULLUP_TO
+ default:
+ break;
+
bogusfrag:
- if (fw_verbose)
- ipfw_report(NULL, ip, rif, oif);
- goto dropit;
+ if (fw_verbose)
+ ipfw_report(NULL, ip, rif, oif);
+ goto dropit;
+
}
rnd_then_got_match:
@@ -865,15 +873,8 @@ got_match:
*cookie = f->fw_number;
return(f->fw_divert_port);
case IP_FW_F_TEE:
- /*
- * XXX someday tee packet here, but beware that you
- * can't use m_copym() or m_copypacket() because
- * the divert input routine modifies the mbuf
- * (and these routines only increment reference
- * counts in the case of mbuf clusters), so need
- * to write custom routine.
- */
- continue;
+ *cookie = f->fw_number;
+ return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
#endif
case IP_FW_F_SKIPTO: /* XXX check */
if ( f->next_rule_ptr )
@@ -884,7 +885,7 @@ got_match:
goto again ;
#ifdef DUMMYNET
case IP_FW_F_PIPE:
- return(f->fw_pipe_nr | 0x10000 );
+ return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG);
#endif
#ifdef IPFIREWALL_FORWARD
case IP_FW_F_FWD:
@@ -968,7 +969,6 @@ dropit:
/*
* Finally, drop the packet.
*/
- /* *cookie = 0; */ /* XXX is this necessary ? */
if (*m) {
m_freem(*m);
*m = NULL;
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 07ac1bb..eb4a999 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -212,6 +212,9 @@ struct ip_fw_chain {
*/
#ifdef KERNEL
+#define IP_FW_PORT_DYNT_FLAG 0x10000
+#define IP_FW_PORT_TEE_FLAG 0x20000
+
/*
* Function definitions.
*/
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 68d7594..feb35a5 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -175,26 +175,21 @@ static struct ip_srcrt {
struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
} ip_srcrt;
-#ifdef IPDIVERT
-/*
- * Shared variable between ip_input() and ip_reass() to communicate
- * about which packets, once assembled from fragments, get diverted,
- * and to which port.
- */
-static u_short frag_divert_port;
-#endif
-
struct sockaddr_in *ip_fw_fwd_addr;
-static void save_rte __P((u_char *, struct in_addr));
-static int ip_dooptions __P((struct mbuf *));
-static void ip_forward __P((struct mbuf *, int));
-static void ip_freef __P((struct ipq *));
-static struct ip *
- ip_reass __P((struct mbuf *, struct ipq *, struct ipq *));
-static struct in_ifaddr *
- ip_rtaddr __P((struct in_addr));
+static void save_rte __P((u_char *, struct in_addr));
+static int ip_dooptions __P((struct mbuf *));
+static void ip_forward __P((struct mbuf *, int));
+static void ip_freef __P((struct ipq *));
+#ifdef IPDIVERT
+static struct ip *ip_reass __P((struct mbuf *,
+ struct ipq *, struct ipq *, u_int32_t *, u_int16_t *));
+#else
+static struct ip *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *));
+#endif
+static struct in_ifaddr *ip_rtaddr __P((struct in_addr));
static void ipintr __P((void));
+
/*
* IP initialization: fill in IP protocol switch table.
* All protocols not implemented in kernel go to raw IP protocol handler.
@@ -245,10 +240,19 @@ ip_input(struct mbuf *m)
struct in_ifaddr *ia;
int i, hlen, mff;
u_short sum;
-#ifndef IPDIVERT /* dummy variable for the firewall code to play with */
- u_short ip_divert_cookie = 0 ;
+ u_int16_t divert_cookie; /* firewall cookie */
+#ifdef IPDIVERT
+ u_int32_t divert_info = 0; /* packet divert/tee info */
+#endif
+ struct ip_fw_chain *rule = NULL;
+
+#ifdef IPDIVERT
+ /* Get and reset firewall cookie */
+ divert_cookie = ip_divert_cookie;
+ ip_divert_cookie = 0;
+#else
+ divert_cookie = 0;
#endif
- struct ip_fw_chain *rule = NULL ;
#if defined(IPFIREWALL) && defined(DUMMYNET)
/*
@@ -375,39 +379,39 @@ iphack:
if (ip_fw_fwd_addr)
goto ours;
#endif /* IPFIREWALL_FORWARD */
- i = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie,
- &m, &rule, &ip_fw_fwd_addr);
/*
- * see the comment in ip_output for the return values
+ * See the comment in ip_output for the return values
* produced by the firewall.
*/
- if (!m) /* packet discarded by firewall */
- return ;
- if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */
- goto pass ;
+ i = (*ip_fw_chk_ptr)(&ip,
+ hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr);
+ if (m == NULL) /* Packet discarded by firewall */
+ return;
+ if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */
+ goto pass;
#ifdef DUMMYNET
- if (i & 0x10000) {
- /* send packet to the appropriate pipe */
+ if ((i & IP_FW_PORT_DYNT_FLAG) != 0) {
+ /* Send packet to the appropriate pipe */
dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule);
- return ;
+ return;
}
#endif
#ifdef IPDIVERT
- if (i > 0 && i < 0x10000) {
- /* Divert packet */
- frag_divert_port = i & 0xffff ;
+ if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
+ /* Divert or tee packet */
+ divert_info = i;
goto ours;
}
#endif
#ifdef IPFIREWALL_FORWARD
if (i == 0 && ip_fw_fwd_addr != NULL)
- goto pass ;
+ goto pass;
#endif
/*
* if we get here, the packet must be dropped
*/
- m_freem(m);
- return;
+ m_freem(m);
+ return;
}
pass:
@@ -550,10 +554,6 @@ ours:
if (m->m_flags & M_EXT) { /* XXX */
if ((m = m_pullup(m, hlen)) == 0) {
ipstat.ips_toosmall++;
-#ifdef IPDIVERT
- frag_divert_port = 0;
- ip_divert_cookie = 0;
-#endif
#ifdef IPFIREWALL_FORWARD
ip_fw_fwd_addr = NULL;
#endif
@@ -620,9 +620,14 @@ found:
if (mff || ip->ip_off) {
ipstat.ips_fragments++;
m->m_pkthdr.header = ip;
+#ifdef IPDIVERT
+ ip = ip_reass(m,
+ fp, &ipq[sum], &divert_info, &divert_cookie);
+#else
ip = ip_reass(m, fp, &ipq[sum]);
+#endif
if (ip == 0) {
-#ifdef IPFIREWALL_FORWARD
+#ifdef IPFIREWALL_FORWARD
ip_fw_fwd_addr = NULL;
#endif
return;
@@ -632,7 +637,8 @@ found:
ipstat.ips_reassembled++;
m = dtom(ip);
#ifdef IPDIVERT
- if (frag_divert_port) {
+ /* Restore original checksum before diverting packet */
+ if (divert_info != 0) {
ip->ip_len += hlen;
HTONS(ip->ip_len);
HTONS(ip->ip_off);
@@ -653,24 +659,35 @@ found:
#ifdef IPDIVERT
/*
- * Divert reassembled packets to the divert protocol if required
- * If divert port is null then cookie should be too,
- * so we shouldn't need to clear them here. Assume ip_divert does so.
+ * 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 (frag_divert_port) {
+ if (divert_info != 0) {
+ struct mbuf *clone = NULL;
+
+ /* Clone packet if we're doing a 'tee' */
+ if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
+ clone = m_dup(m, M_DONTWAIT);
+
+ /* Restore packet header fields to original values */
+ ip->ip_len += hlen;
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+ HTONS(ip->ip_id);
+
+ /* Deliver packet to divert input routine */
+ ip_divert_cookie = divert_cookie;
+ divert_packet(m, 1, divert_info & 0xffff);
ipstat.ips_delivered++;
- ip_divert_port = frag_divert_port;
- frag_divert_port = 0;
- (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen);
- return;
- }
- /* Don't let packets divert themselves */
- if (ip->ip_p == IPPROTO_DIVERT) {
- ipstat.ips_noproto++;
- goto bad;
+ /* If 'tee', continue with original packet */
+ if (clone == NULL)
+ return;
+ m = clone;
+ ip = mtod(m, struct ip *);
}
-
#endif
/*
@@ -711,16 +728,27 @@ ipintr(void)
NETISR_SET(NETISR_IP, ipintr);
/*
- * Take incoming datagram fragment and try to
- * reassemble it into whole datagram. If a chain for
- * reassembly of this datagram already exists, then it
- * is given as fp; otherwise have to make a chain.
+ * Take incoming datagram fragment and try to reassemble it into
+ * whole datagram. If a chain for reassembly of this datagram already
+ * exists, then it is given as fp; otherwise have to make a chain.
+ *
+ * When IPDIVERT enabled, keep additional state with each packet that
+ * tells us if we need to divert or tee the packet we're building.
*/
+
static struct ip *
+#ifdef IPDIVERT
+ip_reass(m, fp, where, divinfo, divcookie)
+#else
ip_reass(m, fp, where)
+#endif
register struct mbuf *m;
register struct ipq *fp;
struct ipq *where;
+#ifdef IPDIVERT
+ u_int32_t *divinfo;
+ u_int16_t *divcookie;
+#endif
{
struct ip *ip = mtod(m, struct ip *);
register struct mbuf *p = 0, *q, *nq;
@@ -752,7 +780,7 @@ ip_reass(m, fp, where)
fp->ipq_frags = m;
m->m_nextpkt = NULL;
#ifdef IPDIVERT
- fp->ipq_divert = 0;
+ fp->ipq_div_info = 0;
fp->ipq_div_cookie = 0;
#endif
goto inserted;
@@ -812,14 +840,13 @@ inserted:
#ifdef IPDIVERT
/*
- * Any fragment diverting causes the whole packet to divert
+ * Transfer firewall instructions to the fragment structure.
+ * Any fragment diverting causes the whole packet to divert.
*/
- if (frag_divert_port) {
- fp->ipq_divert = frag_divert_port;
- fp->ipq_div_cookie = ip_divert_cookie;
- }
- frag_divert_port = 0;
- ip_divert_cookie = 0;
+ fp->ipq_div_info = *divinfo;
+ fp->ipq_div_cookie = *divcookie;
+ *divinfo = 0;
+ *divcookie = 0;
#endif
/*
@@ -863,10 +890,10 @@ inserted:
#ifdef IPDIVERT
/*
- * extract divert port for packet, if any
+ * Extract firewall instructions from the fragment structure.
*/
- frag_divert_port = fp->ipq_divert;
- ip_divert_cookie = fp->ipq_div_cookie;
+ *divinfo = fp->ipq_div_info;
+ *divcookie = fp->ipq_div_cookie;
#endif
/*
@@ -894,8 +921,8 @@ inserted:
dropfrag:
#ifdef IPDIVERT
- frag_divert_port = 0;
- ip_divert_cookie = 0;
+ *divinfo = 0;
+ *divcookie = 0;
#endif
ipstat.ips_fragdropped++;
m_freem(m);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 32200c1..2ed22e6 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -123,15 +123,20 @@ ip_output(m0, opt, ro, flags, imo)
struct sockaddr_in *dst;
struct in_ifaddr *ia;
int isbroadcast;
+ u_int16_t divert_cookie; /* firewall cookie */
#ifdef IPFIREWALL_FORWARD
int fwd_rewrite_src = 0;
#endif
-
-#ifndef IPDIVERT /* dummy variable for the firewall code to play with */
- u_short ip_divert_cookie = 0 ;
+ struct ip_fw_chain *rule = NULL;
+
+#ifdef IPDIVERT
+ /* Get and reset firewall cookie */
+ divert_cookie = ip_divert_cookie;
+ ip_divert_cookie = 0;
+#else
+ divert_cookie = 0;
#endif
- struct ip_fw_chain *rule = NULL ;
-
+
#if defined(IPFIREWALL) && defined(DUMMYNET)
/*
* dummynet packet are prepended a vestigial mbuf with
@@ -418,12 +423,13 @@ sendit:
struct sockaddr_in *old = dst;
off = (*ip_fw_chk_ptr)(&ip,
- hlen, ifp, &ip_divert_cookie, &m, &rule, &dst);
+ hlen, ifp, &divert_cookie, &m, &rule, &dst);
/*
* On return we must do the following:
* m == NULL -> drop the pkt
* 1<=off<= 0xffff -> DIVERT
* (off & 0x10000) -> send to a DUMMYNET pipe
+ * (off & 0x20000) -> TEE the packet
* dst != old -> IPFIREWALL_FORWARD
* off==0, dst==old -> accept
* If some of the above modules is not compiled in, then
@@ -439,7 +445,7 @@ sendit:
if (off == 0 && dst == old) /* common case */
goto pass ;
#ifdef DUMMYNET
- if (off & 0x10000) {
+ if ((off & IP_FW_PORT_DYNT_FLAG) != 0) {
/*
* pass the pkt to dummynet. Need to include
* pipe number, m, ifp, ro, dst because these are
@@ -454,9 +460,27 @@ sendit:
}
#endif
#ifdef IPDIVERT
- if (off > 0 && off < 0x10000) { /* Divert packet */
- ip_divert_port = off & 0xffff ;
- (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, 0);
+ if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
+ struct mbuf *clone = NULL;
+
+ /* Clone packet if we're doing a 'tee' */
+ if ((off & IP_FW_PORT_TEE_FLAG) != 0)
+ clone = m_dup(m, M_DONTWAIT);
+
+ /* Restore packet header fields to original values */
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+
+ /* Deliver packet to divert input routine */
+ ip_divert_cookie = divert_cookie;
+ divert_packet(m, 0, off & 0xffff);
+
+ /* If 'tee', continue with original packet */
+ if (clone != NULL) {
+ m = clone;
+ ip = mtod(m, struct ip *);
+ goto pass;
+ }
goto done;
}
#endif
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 1b69ec2..c56a340 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -62,8 +62,8 @@ struct ipq {
struct mbuf *ipq_frags; /* to ip headers of fragments */
struct in_addr ipq_src,ipq_dst;
#ifdef IPDIVERT
- u_short ipq_divert; /* divert protocol port */
- u_short ipq_div_cookie; /* divert protocol cookie */
+ u_int32_t ipq_div_info; /* ipfw divert port & flags */
+ u_int16_t ipq_div_cookie; /* ipfw divert cookie */
#endif
};
@@ -179,9 +179,9 @@ void ip_rsvp_force_done __P((struct socket *));
#ifdef IPDIVERT
void div_init __P((void));
void div_input __P((struct mbuf *, int));
+void divert_packet __P((struct mbuf *, int, int));
extern struct pr_usrreqs div_usrreqs;
-extern u_short ip_divert_port;
-extern u_short ip_divert_cookie;
+extern u_int16_t ip_divert_cookie;
#endif
extern struct sockaddr_in *ip_fw_fwd_addr;
OpenPOWER on IntegriCloud