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.
This commit is contained in:
Luigi Rizzo 2000-01-08 11:31:43 +00:00
parent d1f04b29f0
commit ec8fac2acf
2 changed files with 99 additions and 69 deletions

View File

@ -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;

View File

@ -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