Cleanup the interface to ip_fw_chk, two of the input arguments

were totally useless and have been removed.

ip_input.c, ip_output.c:
    Properly initialize the "ip" pointer in case the firewall does an
    m_pullup() on the packet.

    Remove some debugging code forgotten long ago.

ip_fw.[ch], bridge.c:
    Prepare the grounds for matching MAC header fields in bridged packets,
    so we can have 'etherfw' functionality without a lot of kernel and
    userland bloat.
This commit is contained in:
Luigi Rizzo 2002-05-09 10:34:57 +00:00
parent d8f4f6a404
commit d60315bef5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=96245
5 changed files with 144 additions and 142 deletions

View file

@ -859,15 +859,10 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
#endif
(IPFW_LOADED && bdg_ipfw != 0))) {
struct ip *ip ;
int i;
if (rule != NULL) /* dummynet packet, already partially processed */
goto forward; /* HACK! I should obey the fw_one_pass */
if (ntohs(save_eh.ether_type) != ETHERTYPE_IP)
goto forward ; /* not an IP packet, ipfw is not appropriate */
if (m0->m_pkthdr.len < sizeof(struct ip) )
goto forward ; /* header too short for an IP pkt, cannot filter */
/*
* i need some amt of data to be contiguous, and in case others need
* the packet (shared==1) also better be in the first mbuf.
@ -881,48 +876,51 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
}
}
/*
* before calling the firewall, swap fields the same as IP does.
* here we assume the pkt is an IP one and the header is contiguous
*/
ip = mtod(m0, struct ip *);
ip->ip_len = ntohs(ip->ip_len);
ip->ip_off = ntohs(ip->ip_off);
#ifdef PFIL_HOOKS
/*
* NetBSD-style generic packet filter, pfil(9), hooks.
* Enables ipf(8) in bridging.
*/
#ifdef PFIL_HOOKS
for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
if (pfh->pfil_func) {
rv = pfh->pfil_func(ip, ip->ip_hl << 2, src, 0, &m0);
if (rv != 0 || m0 == NULL)
return m0;
ip = mtod(m0, struct ip *);
}
if (m0->m_pkthdr.len >= sizeof(struct ip) &&
ntohs(save_eh.ether_type) == ETHERTYPE_IP) {
/*
* before calling the firewall, swap fields the same as IP does.
* here we assume the pkt is an IP one and the header is contiguous
*/
struct ip *ip = mtod(m0, struct ip *);
ip->ip_len = ntohs(ip->ip_len);
ip->ip_off = ntohs(ip->ip_off);
for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
if (pfh->pfil_func) {
rv = pfh->pfil_func(ip, ip->ip_hl << 2, src, 0, &m0);
if (rv != 0 || m0 == NULL)
return m0;
ip = mtod(m0, struct ip *);
}
/*
* If we get here, the firewall has passed the pkt, but the mbuf
* pointer might have changed. Restore ip and the fields ntohs()'d.
*/
ip = mtod(m0, struct ip *);
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
}
#endif /* PFIL_HOOKS */
/*
* The third parameter to the firewall code is the dst. interface.
* 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.
*/
if (IPFW_LOADED && bdg_ipfw != 0) {
i = ip_fw_chk_ptr(&ip, 0, NULL, NULL /* cookie */, &m0, &rule, NULL);
if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */
return m0 ;
} else
i = 0; /* Treat it as a "pass" when not using ipfw. */
/*
* If we get here, the firewall has passed the pkt, but the mbuf
* pointer might have changed. Restore ip and the fields ntohs()'d.
*/
ip = mtod(m0, struct ip *);
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
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);
if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */
return m0 ;
if (i == 0) /* a PASS rule. */
goto forward ;

View file

@ -222,16 +222,13 @@ static __inline int
int range_flag, int mask);
static int tcpflg_match (struct tcphdr *tcp, struct ip_fw *f);
static int icmptype_match (struct icmp * icmp, struct ip_fw * f);
static void ipfw_report (struct ip_fw *f, struct ip *ip, int offset,
static void ipfw_report (struct ip_fw *f, struct ip *ip, int ip_off,
int ip_len, struct ifnet *rif,
struct ifnet *oif);
static void flush_rule_ptrs(void);
static int ip_fw_chk (struct ip **pip, int hlen,
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
struct ip_fw **flow_id,
struct sockaddr_in **next_hop);
static ip_fw_chk_t ip_fw_chk;
static int ip_fw_ctl (struct sockopt *sopt);
ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;
@ -509,7 +506,7 @@ iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
}
static void
ipfw_report(struct ip_fw *f, struct ip *ip, int offset, int ip_len,
ipfw_report(struct ip_fw *f, struct ip *ip, int ip_off, int ip_len,
struct ifnet *rif, struct ifnet *oif)
{
struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl);
@ -519,6 +516,7 @@ ipfw_report(struct ip_fw *f, struct ip *ip, int offset, int ip_len,
char *action;
char action2[32], proto[47], name[18], fragment[27];
int len;
int offset = ip_off & IP_OFFMASK;
count = f ? f->fw_pcnt : ++counter;
if ((f == NULL && fw_verbose_limit != 0 && count > fw_verbose_limit) ||
@ -634,11 +632,11 @@ ipfw_report(struct ip_fw *f, struct ip *ip, int offset, int ip_len,
break;
}
if (ip->ip_off & (IP_MF | IP_OFFMASK))
if (ip_off & (IP_MF | IP_OFFMASK))
snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)",
ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
offset << 3,
(ip->ip_off & IP_MF) ? "+" : "");
(ip_off & IP_MF) ? "+" : "");
else
fragment[0] = '\0';
if (oif)
@ -1061,15 +1059,14 @@ lookup_next_rule(struct ip_fw *me)
/*
* Parameters:
*
* pip Pointer to packet header (struct ip **)
* hlen Packet header length
* *m The packet; we set to NULL when/if we nuke it.
* 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.
* Special case: cookie == NULL on input for bridging.
* *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).
* For bridged packets, this is a pointer to the MAC header.
*
* Return value:
*
@ -1087,32 +1084,38 @@ lookup_next_rule(struct ip_fw *me)
*/
static int
ip_fw_chk(struct ip **pip, int hlen,
struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
struct ip_fw **flow_id,
struct sockaddr_in **next_hop)
ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie,
struct ip_fw **flow_id, struct sockaddr_in **next_hop)
{
struct ip_fw *f = NULL; /* matching rule */
struct ip *ip = *pip;
struct ip *ip = mtod(*m, struct ip *);
struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
struct ifnet *tif;
u_int hlen = ip->ip_hl << 2;
struct ether_header * eh = NULL;
u_short offset = 0 ;
u_short ip_off=0, offset = 0 ;
/* local copy of addresses for faster matching */
u_short src_port = 0, dst_port = 0;
struct in_addr src_ip, dst_ip; /* XXX */
u_int8_t proto= 0, flags = 0 ; /* XXX */
struct in_addr src_ip, dst_ip;
u_int8_t proto= 0, flags = 0;
u_int16_t skipto, bridgeCookie;
u_int16_t ip_len;
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 ;
/* Special hack for bridging (as usual) */
if (cookie == NULL) {
#define BRIDGED (cookie == &bridgeCookie)
if (cookie == NULL) { /* this is a bridged packet */
bridgeCookie = 0;
cookie = &bridgeCookie;
#define BRIDGED (cookie == &bridgeCookie)
eh = (struct ether_header *)next_hop;
if ( (*m)->m_pkthdr.len >= sizeof(struct ip) &&
ntohs(eh->ether_type) == ETHERTYPE_IP)
hlen = ip->ip_hl << 2;
} else {
hlen = ip->ip_hl << 2;
}
@ -1120,63 +1123,67 @@ ip_fw_chk(struct ip **pip, int hlen,
skipto = *cookie;
*cookie = 0;
#define PULLUP_TO(len) do { \
if ((*m)->m_len < (len)) { \
ip = NULL ; \
if ((*m = m_pullup(*m, (len))) == 0) \
goto bogusfrag; \
ip = mtod(*m, struct ip *); \
*pip = ip; \
} \
} while (0)
/*
* Collect parameters into local variables for faster matching.
*/
proto = ip->ip_p;
src_ip = ip->ip_src;
dst_ip = ip->ip_dst;
if (0 && BRIDGED) { /* not yet... */
offset = (ntohs(ip->ip_off) & IP_OFFMASK);
ip_len = ntohs(ip->ip_len);
} else {
offset = (ip->ip_off & IP_OFFMASK);
ip_len = ip->ip_len;
}
if (offset == 0) {
switch (proto) {
case IPPROTO_TCP : {
struct tcphdr *tcp;
if (hlen > 0) { /* this is an IP packet */
proto = ip->ip_p;
src_ip = ip->ip_src;
dst_ip = ip->ip_dst;
if (BRIDGED) { /* not yet... */
ip_off = ntohs(ip->ip_off);
ip_len = ntohs(ip->ip_len);
} else {
ip_off = ip->ip_off;
ip_len = ip->ip_len;
}
offset = ip_off & IP_OFFMASK;
if (offset == 0) {
PULLUP_TO(hlen + sizeof(struct tcphdr));
tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl);
dst_port = tcp->th_dport ;
src_port = tcp->th_sport ;
flags = tcp->th_flags ;
#define PULLUP_TO(len) \
do { \
if ((*m)->m_len < (len)) { \
*m = m_pullup(*m, (len)); \
if (*m == 0) \
goto bogusfrag; \
ip = mtod(*m, struct ip *); \
} \
} while (0)
switch (proto) {
case IPPROTO_TCP : {
struct tcphdr *tcp;
PULLUP_TO(hlen + sizeof(struct tcphdr));
tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl);
dst_port = tcp->th_dport ;
src_port = tcp->th_sport ;
flags = tcp->th_flags ;
}
break ;
case IPPROTO_UDP : {
struct udphdr *udp;
PULLUP_TO(hlen + sizeof(struct udphdr));
udp =(struct udphdr *)((u_int32_t *)ip + ip->ip_hl);
dst_port = udp->uh_dport ;
src_port = udp->uh_sport ;
}
break;
case IPPROTO_ICMP:
PULLUP_TO(hlen + 4); /* type, code and checksum. */
flags = ((struct icmp *)
((u_int32_t *)ip + ip->ip_hl))->icmp_type ;
break ;
default :
break;
}
break ;
case IPPROTO_UDP : {
struct udphdr *udp;
PULLUP_TO(hlen + sizeof(struct udphdr));
udp =(struct udphdr *)((u_int32_t *)ip + ip->ip_hl);
dst_port = udp->uh_dport ;
src_port = udp->uh_sport ;
}
break;
case IPPROTO_ICMP:
PULLUP_TO(hlen + 4); /* type, code and checksum. */
flags = ((struct icmp *)
((u_int32_t *)ip + ip->ip_hl))->icmp_type ;
break ;
default :
break;
#undef PULLUP_TO
}
}
#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;
@ -1471,8 +1478,8 @@ ip_fw_chk(struct ip **pip, int hlen,
bogusfrag:
if (fw_verbose) {
if (ip != NULL)
ipfw_report(NULL, ip, offset, ip_len, rif, oif);
if (*m != NULL)
ipfw_report(NULL, ip, ip_off, ip_len, rif, oif);
else
printf("pullup failed\n");
}
@ -1498,8 +1505,8 @@ ip_fw_chk(struct ip **pip, int hlen,
f->timestamp = time_second;
/* Log to console if desired */
if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
ipfw_report(f, ip, offset, ip_len, rif, oif);
if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose && hlen >0)
ipfw_report(f, ip, ip_off, ip_len, rif, oif);
/* Take appropriate action */
switch (f->fw_flg & IP_FW_F_COMMAND) {

View file

@ -49,11 +49,26 @@ union ip_fw_if {
* Port numbers are stored in HOST byte order.
*/
/*
* To match MAC headers:
* 12 bytes at fw_mac_hdr contain the dst-src MAC address after masking.
* 12 bytes at fw_mac_mask contain the mask to apply to dst-src
* 2 bytes at fw_mac_type contain the mac type after mask (in net format)
* 2 bytes at fw_mac_type_mask contain the mac type mask
* If IP_FW_F_SRNG, the two contain the low-high of a range of types.
* IP_FW_F_DRNG is used to indicare we want to match a vlan.
*/
#define fw_mac_hdr fw_src
#define fw_mac_mask fw_uar
#define fw_mac_type fw_iplen
#define fw_mac_mask_type fw_ipid
struct ip_fw {
LIST_ENTRY(ip_fw) next; /* bidirectional list of rules */
u_int fw_flg; /* Operational Flags word */
u_int64_t fw_pcnt; /* Packet counters */
u_int64_t fw_bcnt; /* Byte counters */
struct in_addr fw_src; /* Source IP address */
struct in_addr fw_dst; /* Destination IP address */
struct in_addr fw_smsk; /* Mask for source IP address */
@ -238,8 +253,9 @@ struct ipfw_dyn_rule {
#define IP_FW_F_CHECK_S 0x10000000 /* check state */
#define IP_FW_F_SME 0x20000000 /* source = me */
#define IP_FW_F_DME 0x40000000 /* destination = me */
#define IP_FW_F_MAC 0x80000000 /* match MAC header */
#define IP_FW_F_MASK 0x7FFFFFFF /* All possible flag bits mask */
#define IP_FW_F_MASK 0xFFFFFFFF /* All possible flag bits mask */
/*
* Flags for the 'fw_ipflg' field, for comparing values
@ -320,8 +336,8 @@ void ip_fw_init(void);
/* Firewall hooks */
struct ip;
struct sockopt;
typedef int ip_fw_chk_t (struct ip **, int, struct ifnet *, u_int16_t *,
struct mbuf **, struct ip_fw **, struct sockaddr_in **);
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_ctl_t (struct sockopt *);
extern ip_fw_chk_t *ip_fw_chk_ptr;
extern ip_fw_ctl_t *ip_fw_ctl_ptr;

View file

@ -450,22 +450,14 @@ ip_input(struct mbuf *m)
* See the comment in ip_output for the return values
* produced by the firewall.
*/
i = ip_fw_chk_ptr(&ip, hlen, NULL,
&divert_cookie, &m, &rule, &ip_fw_fwd_addr);
if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */
i = ip_fw_chk_ptr(&m, NULL /* oif */, &divert_cookie,
&rule, &ip_fw_fwd_addr);
if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
if (m)
m_freem(m);
return;
}
if (m == NULL) { /* Packet discarded by firewall */
static int __debug=10;
if (__debug > 0) {
printf(
"firewall returns NULL, please update!\n");
__debug--;
}
return;
}
ip = mtod(m, struct ip *); /* just in case m changed */
if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */
goto pass;
if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {

View file

@ -610,8 +610,7 @@ ip_output(m0, opt, ro, flags, imo)
if (fw_enable && IPFW_LOADED && !ip_fw_fwd_addr) {
struct sockaddr_in *old = dst;
off = ip_fw_chk_ptr(&ip,
hlen, ifp, &divert_cookie, &m, &rule, &dst);
off = ip_fw_chk_ptr(&m, ifp, &divert_cookie, &rule, &dst);
/*
* On return we must do the following:
* m == NULL -> drop the pkt (old interface, deprecated)
@ -627,23 +626,13 @@ ip_output(m0, opt, ro, flags, imo)
* unsupported rules), but better play safe and drop
* packets in case of doubt.
*/
if (off & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */
if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
if (m)
m_freem(m);
error = EACCES;
goto done;
}
if (!m) { /* firewall said to reject */
static int __debug=10;
if (__debug > 0) {
printf(
"firewall returns NULL, please update!\n");
__debug--;
}
error = EACCES;
goto done;
}
ip = mtod(m, struct ip *);
if (off == 0 && dst == old) /* common case */
goto pass;
if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) {