diff options
author | luigi <luigi@FreeBSD.org> | 2000-01-08 11:31:43 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2000-01-08 11:31:43 +0000 |
commit | dba91948d0bc7911c09aa3cc2cdcda90833faada (patch) | |
tree | b603422213f5e17a7b4092c53696b434635f857f /sys/netinet | |
parent | 7f185791a639766b0028bb723c7a8c20d76b4cfd (diff) | |
download | FreeBSD-src-dba91948d0bc7911c09aa3cc2cdcda90833faada.zip FreeBSD-src-dba91948d0bc7911c09aa3cc2cdcda90833faada.tar.gz |
Add ipfw hooks for the new dummynet features.
Support masks on TCP/UDP ports.
Minor cleanup of ip_fw_chk() to avoid repeated calls to PULLUP_TO
at each rule.
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/ip_fw.c | 163 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 5 |
2 files changed, 99 insertions, 69 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index b897421..a7e235e 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -89,7 +89,7 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "Enable printing of debug ip_fw statements"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, - "Only do a single pass through ipfw rules when using divert(4)"); + "Only do a single pass through ipfw when using divert(4)/dummynet(4)"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "Log matches to ipfw rules"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, @@ -113,7 +113,7 @@ static __inline int static int ipopts_match __P((struct ip *ip, struct ip_fw *f)); static __inline int port_match __P((u_short *portptr, int nports, u_short port, - int range_flag)); + int range_flag, int mask)); static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f)); static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); static void ipfw_report __P((struct ip_fw *f, struct ip *ip, @@ -133,10 +133,16 @@ static char err_prefix[] = "ip_fw_ctl:"; * Returns 1 if the port is matched by the vector, 0 otherwise */ static __inline int -port_match(u_short *portptr, int nports, u_short port, int range_flag) +port_match(u_short *portptr, int nports, u_short port, int range_flag, int mask) { if (!nports) return 1; + if (mask) { + if ( 0 == ((portptr[0] ^ port) & portptr[1]) ) + return 1; + nports -= 2; + portptr += 2; + } if (range_flag) { if (portptr[0] <= port && port <= portptr[1]) { return 1; @@ -508,13 +514,33 @@ ip_fw_chk(struct ip **pip, int hlen, struct ip *ip = NULL ; struct ifnet *const rif = (*m)->m_pkthdr.rcvif; u_short offset = 0 ; - u_short src_port, dst_port; + u_short src_port = 0, dst_port = 0; + struct in_addr src_ip, dst_ip; /* XXX */ + u_int8_t proto= 0 ; /* XXX */ u_int16_t skipto; /* Grab and reset cookie */ skipto = *cookie; *cookie = 0; +/* + * 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 ); \ + if ((*m)->m_len < (len) ) { \ + if ( (*m = m_pullup(*m, (len))) == 0) \ + goto bogusfrag; \ + ip = mtod(*m, struct ip *); \ + if (pip) \ + *pip = ip ; \ + else \ + ip = (struct ip *)((char *)ip + 14);\ + offset = (ip->ip_off & IP_OFFMASK); \ + } \ + } while (0) + if (pip) { /* normal ip packet */ ip = *pip; offset = (ip->ip_off & IP_OFFMASK); @@ -542,12 +568,53 @@ non_ip: ip = NULL ; } } + /* + * collect parameters into local variables for faster matching. + */ + if (ip) { + struct tcphdr *tcp; + struct udphdr *udp; + + dst_ip = ip->ip_dst ; + src_ip = ip->ip_src ; + proto = ip->ip_p ; + switch (proto) { + case IPPROTO_TCP : + PULLUP_TO(hlen + 14); + tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl); + dst_port = tcp->th_dport ; + src_port = tcp->th_sport ; + break ; + + case IPPROTO_UDP : + PULLUP_TO(hlen + 4); + 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 + 2); + break ; + + default : + src_port = dst_port = 0 ; + } +#undef PULLUP_TO +#ifdef DUMMYNET + dn_last_pkt.src_ip = ntohl(src_ip.s_addr) ; + dn_last_pkt.dst_ip = ntohl(dst_ip.s_addr) ; + dn_last_pkt.proto = proto ; + dn_last_pkt.src_port = ntohs(src_port) ; + dn_last_pkt.dst_port = ntohs(dst_port) ; +#endif + } + if (*flow_id) { /* Accept if passed first test */ if (fw_one_pass) return 0; - /* * Packet has already been tagged. Look for the next rule * to restart processing. @@ -562,7 +629,7 @@ non_ip: ip = NULL ; } else { /* * Go down the chain, looking for enlightment. - * If we've been asked to start at a given rule, do so + * If we've been asked to start at a given rule, do so. */ chain = LIST_FIRST(&ip_fw_chain); if (skipto != 0) { @@ -574,10 +641,13 @@ non_ip: ip = NULL ; goto dropit; } } + for (; chain; chain = LIST_NEXT(chain, chain)) { register struct ip_fw * f ; again: f = chain->rule; + if (f->fw_number == IPFW_DEFAULT_RULE) + goto got_match ; if (oif) { /* Check direction outbound */ @@ -594,12 +664,6 @@ again: * after this, only goto got_match or continue */ struct ether_header *eh = mtod(*m, struct ether_header *); - - /* - * make default rule always match or we have a panic - */ - if (f->fw_number == IPFW_DEFAULT_RULE) - goto got_match ; /* * temporary hack: * udp from 0.0.0.0 means this rule applies. @@ -628,12 +692,12 @@ again: continue; /* If src-addr doesn't match, not this rule. */ - if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr + if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((src_ip.s_addr & f->fw_smsk.s_addr) != f->fw_src.s_addr)) continue; /* If dest-addr doesn't match, not this rule. */ - if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr + if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((dst_ip.s_addr & f->fw_dmsk.s_addr) != f->fw_dst.s_addr)) continue; @@ -668,33 +732,14 @@ again: goto rnd_then_got_match; } else /* If different, don't match */ - if (ip->ip_p != f->fw_prot) + if (proto != f->fw_prot) continue; -/* - * 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 ); \ - if ((*m)->m_len < (len) ) { \ - if ( (*m = m_pullup(*m, (len))) == 0) \ - goto bogusfrag; \ - ip = mtod(*m, struct ip *); \ - if (pip) \ - *pip = ip ; \ - else \ - ip = (struct ip *)((char *)ip + 14);\ - offset = (ip->ip_off & IP_OFFMASK); \ - } \ - } while (0) - /* Protocol specific checks for uid only */ if (f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)) { - switch (ip->ip_p) { + switch (proto) { case IPPROTO_TCP: { - struct tcphdr *tcp; struct inpcb *P; if (offset == 1) /* cf. RFC 1858 */ @@ -702,16 +747,13 @@ again: if (offset != 0) continue; - PULLUP_TO(hlen + 14); - tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl); - if (oif) - P = in_pcblookup_hash(&tcbinfo, ip->ip_dst, - tcp->th_dport, ip->ip_src, tcp->th_sport, 0, + P = in_pcblookup_hash(&tcbinfo, dst_ip, + dst_port, src_ip, src_port, 0, oif); else - P = in_pcblookup_hash(&tcbinfo, ip->ip_src, - tcp->th_sport, ip->ip_dst, tcp->th_dport, 0, + P = in_pcblookup_hash(&tcbinfo, src_ip, + src_port, dst_ip, dst_port, 0, NULL); if (P && P->inp_socket) { @@ -729,22 +771,18 @@ again: case IPPROTO_UDP: { - struct udphdr *udp; struct inpcb *P; if (offset != 0) continue; - PULLUP_TO(hlen + 4); - udp =(struct udphdr *)((u_int32_t *)ip + ip->ip_hl); - if (oif) - P = in_pcblookup_hash(&udbinfo, ip->ip_dst, - udp->uh_dport, ip->ip_src, udp->uh_sport, 1, + P = in_pcblookup_hash(&udbinfo, dst_ip, + dst_port, src_ip, src_port, 1, oif); else - P = in_pcblookup_hash(&udbinfo, ip->ip_src, - udp->uh_sport, ip->ip_dst, udp->uh_dport, 1, + P = in_pcblookup_hash(&udbinfo, src_ip, + src_port, dst_ip, dst_port, 1, NULL); if (P && P->inp_socket) { @@ -766,7 +804,7 @@ again: } /* Protocol specific checks */ - switch (ip->ip_p) { + switch (proto) { case IPPROTO_TCP: { struct tcphdr *tcp; @@ -785,19 +823,13 @@ again: break; } - PULLUP_TO(hlen + 14); tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f)) continue; - src_port = ntohs(tcp->th_sport); - dst_port = ntohs(tcp->th_dport); goto check_ports; } case IPPROTO_UDP: - { - struct udphdr *udp; - if (offset != 0) { /* * Port specification is unavailable -- if this @@ -809,21 +841,18 @@ again: break; } - PULLUP_TO(hlen + 4); - udp = (struct udphdr *) ((u_int32_t *)ip + ip->ip_hl); - src_port = ntohs(udp->uh_sport); - dst_port = ntohs(udp->uh_dport); check_ports: if (!port_match(&f->fw_uar.fw_pts[0], - IP_FW_GETNSRCP(f), src_port, - f->fw_flg & IP_FW_F_SRNG)) + IP_FW_GETNSRCP(f), ntohs(src_port), + f->fw_flg & IP_FW_F_SRNG, + f->fw_flg & IP_FW_F_SMSK)) continue; if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)], - IP_FW_GETNDSTP(f), dst_port, - f->fw_flg & IP_FW_F_DRNG)) + IP_FW_GETNDSTP(f), ntohs(dst_port), + f->fw_flg & IP_FW_F_DRNG, + f->fw_flg & IP_FW_F_DMSK)) continue; break; - } case IPPROTO_ICMP: { @@ -831,13 +860,11 @@ check_ports: if (offset != 0) /* Type isn't valid */ break; - PULLUP_TO(hlen + 2); icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl); if (!icmptype_match(icmp, f)) continue; break; } -#undef PULLUP_TO default: break; diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 11c56a4..ffd1d04 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -171,8 +171,11 @@ struct ip_fw_chain { #define IP_FW_F_GID 0x00400000 /* filter by gid */ #define IP_FW_F_RND_MATCH 0x00800000 /* probabilistic rule match */ +#define IP_FW_F_SMSK 0x01000000 /* src-port + mask */ +#define IP_FW_F_DMSK 0x02000000 /* dst-port + mask */ +#define IP_FW_F_KEEP_S 0x04000000 /* keep state */ -#define IP_FW_F_MASK 0x00FFFFFF /* All possible flag bits mask */ +#define IP_FW_F_MASK 0x03FFFFFF /* All possible flag bits mask */ /* * For backwards compatibility with rules specifying "via iface" but |