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
This commit is contained in:
Archie Cobbs 1999-12-06 00:43:07 +00:00
parent 02ebab9383
commit 8948e4ba8e
6 changed files with 234 additions and 191 deletions

View File

@ -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;
}

View File

@ -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 @@ non_ip: ip = NULL ;
* 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 @@ non_ip: ip = NULL ;
} else if (!groupmember(f->fw_gid,
P->inp_socket->so_cred))
continue;
} else continue;
} else
continue;
break;
}
@ -737,24 +751,14 @@ non_ip: ip = NULL ;
} 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 @@ non_ip: ip = NULL ;
}
#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 @@ non_ip: ip = NULL ;
*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 @@ non_ip: ip = NULL ;
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 @@ non_ip: ip = NULL ;
/*
* Finally, drop the packet.
*/
/* *cookie = 0; */ /* XXX is this necessary ? */
if (*m) {
m_freem(*m);
*m = NULL;

View File

@ -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.
*/

View File

@ -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 @@ ip_input(struct mbuf *m)
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 @@ ip_input(struct mbuf *m)
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 @@ ip_input(struct mbuf *m)
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 @@ ip_input(struct mbuf *m)
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 @@ ip_input(struct mbuf *m)
#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 @@ ip_reass(m, fp, where)
#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 @@ ip_reass(m, fp, where)
#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 @@ ip_reass(m, fp, where)
dropfrag:
#ifdef IPDIVERT
frag_divert_port = 0;
ip_divert_cookie = 0;
*divinfo = 0;
*divcookie = 0;
#endif
ipstat.ips_fragdropped++;
m_freem(m);

View File

@ -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 @@ ip_output(m0, opt, ro, flags, imo)
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 @@ ip_output(m0, opt, ro, flags, imo)
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 @@ ip_output(m0, opt, ro, flags, imo)
}
#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

View File

@ -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;