diff options
-rw-r--r-- | sys/net/bridge.c | 70 | ||||
-rw-r--r-- | sys/netinet/ip_fw.c | 157 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 22 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 16 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 17 |
5 files changed, 142 insertions, 140 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c index 9b029b2..48a31cc 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -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 ; diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index e552e1d..b06576a 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -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; - - 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 ; + 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) { + +#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) - case IPPROTO_UDP : { - struct udphdr *udp; + 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 ; - 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_UDP : { + struct udphdr *udp; - case IPPROTO_ICMP: - PULLUP_TO(hlen + 4); /* type, code and checksum. */ - flags = ((struct icmp *) - ((u_int32_t *)ip + ip->ip_hl))->icmp_type ; - break ; + 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; - default : - 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 @@ check_ports: 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 @@ got_match: 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) { diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 468d66f..c41eb31 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -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; diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index b720bdd..79d5123 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -450,22 +450,14 @@ iphack: * 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) { diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index d3628f1..d9d2145 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -610,8 +610,7 @@ skip_ipsec: 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 @@ skip_ipsec: * 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) { |