summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2000-01-08 11:31:43 +0000
committerluigi <luigi@FreeBSD.org>2000-01-08 11:31:43 +0000
commitdba91948d0bc7911c09aa3cc2cdcda90833faada (patch)
treeb603422213f5e17a7b4092c53696b434635f857f /sys/netinet
parent7f185791a639766b0028bb723c7a8c20d76b4cfd (diff)
downloadFreeBSD-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.c163
-rw-r--r--sys/netinet/ip_fw.h5
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
OpenPOWER on IntegriCloud