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:
parent
d1f04b29f0
commit
ec8fac2acf
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user