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:
parent
02ebab9383
commit
8948e4ba8e
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user