Introduce a new feature in IPFW: Check of the source or destination

address is configured on a interface.  This is useful for routers with
dynamic interfaces.  It is now possible to say:

        0100 allow       tcp from any to any established
        0200 skipto 1000 tcp from any to any
        0300 allow       ip from any to any
        1000 allow       tcp from 1.2.3.4 to me 22
        1010 deny        tcp from any to me 22
        1020 allow       tcp from any to any

and not have to worry about the behaviour if dynamic interfaces configure
new IP numbers later on.

The check is semi expensive (traverses the interface address list)
so it should be protected as in the above example if high performance
is a requirement.
This commit is contained in:
Poul-Henning Kamp 2001-02-13 14:12:37 +00:00
parent 6d110b1be0
commit bb07ec8c84
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=72440
4 changed files with 87 additions and 39 deletions

View File

@ -478,9 +478,23 @@ or
.Cm all
keywords mean any protocol will match.
.It Ar src No and Ar dst :
.Cm any
|
.Cm me
|
.Op Cm not
.Aq Ar address Ns / Ns Ar mask
.Op Ar ports
.Pp
Specifying
.Cm any
makes the rule match any IP number.
.Pp
Specifying
.Cm me
makes the rule match any IP number configured on an interface in the system.
This is an computationally semi-expensive check which should be used with care.
.Pp
The
.Aq Ar address Ns / Ns Ar mask
may be specified as:

View File

@ -276,17 +276,20 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
else
printf(" %u", chain->fw_prot);
printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
if (chain->fw_flg & IP_FW_F_SME) {
printf(" from me");
} else {
printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
adrt=ntohl(chain->fw_smsk.s_addr);
if (adrt==ULONG_MAX && do_resolv) {
adrt=(chain->fw_src.s_addr);
he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
if (he==NULL) {
printf(inet_ntoa(chain->fw_src));
} else
printf("%s",he->h_name);
} else {
adrt=ntohl(chain->fw_smsk.s_addr);
if (adrt==ULONG_MAX && do_resolv) {
adrt=(chain->fw_src.s_addr);
he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
if (he==NULL) {
printf(inet_ntoa(chain->fw_src));
} else
printf("%s",he->h_name);
} else {
if (adrt!=ULONG_MAX) {
mb=mask_bits(chain->fw_smsk);
if (mb == 0) {
@ -303,6 +306,7 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
}
} else
printf(inet_ntoa(chain->fw_src));
}
}
if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
@ -318,33 +322,37 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
}
}
printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
if (chain->fw_flg & IP_FW_F_DME) {
printf(" to me");
} else {
printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
adrt=ntohl(chain->fw_dmsk.s_addr);
if (adrt==ULONG_MAX && do_resolv) {
adrt=(chain->fw_dst.s_addr);
he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
if (he==NULL) {
printf(inet_ntoa(chain->fw_dst));
} else
printf("%s",he->h_name);
} else {
if (adrt!=ULONG_MAX) {
mb=mask_bits(chain->fw_dmsk);
if (mb == 0) {
printf("any");
} else {
if (mb > 0) {
printf(inet_ntoa(chain->fw_dst));
printf("/%d",mb);
adrt=ntohl(chain->fw_dmsk.s_addr);
if (adrt==ULONG_MAX && do_resolv) {
adrt=(chain->fw_dst.s_addr);
he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
if (he==NULL) {
printf(inet_ntoa(chain->fw_dst));
} else
printf("%s",he->h_name);
} else {
if (adrt!=ULONG_MAX) {
mb=mask_bits(chain->fw_dmsk);
if (mb == 0) {
printf("any");
} else {
printf(inet_ntoa(chain->fw_dst));
printf(":");
printf(inet_ntoa(chain->fw_dmsk));
if (mb > 0) {
printf(inet_ntoa(chain->fw_dst));
printf("/%d",mb);
} else {
printf(inet_ntoa(chain->fw_dst));
printf(":");
printf(inet_ntoa(chain->fw_dmsk));
}
}
}
} else
printf(inet_ntoa(chain->fw_dst));
} else
printf(inet_ntoa(chain->fw_dst));
}
}
if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
@ -857,8 +865,8 @@ show_usage(const char *fmt, ...)
" reset|count|skipto num|divert port|tee port|fwd ip|\n"
" pipe num} [log [logamount count]]\n"
" proto: {ip|tcp|udp|icmp|<number>}\n"
" src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
" dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
" src: from [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
" dst: to [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
" extras:\n"
" uid {user id}\n"
" gid {group id}\n"
@ -1792,7 +1800,12 @@ add(ac,av)
if (!ac)
show_usage("missing arguments");
fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
if (ac && !strncmp(*av,"me",strlen(*av))) {
rule.fw_flg |= IP_FW_F_SME;
av++; ac--;
} else {
fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
}
if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
u_short nports = 0;
@ -1819,7 +1832,13 @@ add(ac,av)
if (!ac)
show_usage("missing arguments");
fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
if (ac && !strncmp(*av,"me",strlen(*av))) {
rule.fw_flg |= IP_FW_F_DME;
av++; ac--;
} else {
fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
}
if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
u_short nports = 0;

View File

@ -47,6 +47,7 @@
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/in_pcb.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
@ -947,6 +948,7 @@ ip_fw_chk(struct ip **pip, int hlen,
struct ip_fw *f = NULL, *rule = NULL;
struct ip *ip = *pip;
struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
struct ifnet *tif;
u_short offset = 0 ;
u_short src_port = 0, dst_port = 0;
struct in_addr src_ip, dst_ip; /* XXX */
@ -1111,6 +1113,16 @@ ip_fw_chk(struct ip **pip, int hlen,
if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 )
continue;
if (f->fw_flg & IP_FW_F_SME) {
INADDR_TO_IFP(src_ip, tif);
if (tif == NULL)
continue;
}
if (f->fw_flg & IP_FW_F_DME) {
INADDR_TO_IFP(dst_ip, tif);
if (tif == NULL)
continue;
}
/* If src-addr doesn't match, not this rule. */
if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((src_ip.s_addr
& f->fw_smsk.s_addr) != f->fw_src.s_addr))

View File

@ -212,7 +212,10 @@ struct ipfw_dyn_rule {
#define IP_FW_F_KEEP_S 0x08000000 /* keep state */
#define IP_FW_F_CHECK_S 0x10000000 /* check state */
#define IP_FW_F_MASK 0x1FFFFFFF /* All possible flag bits mask */
#define IP_FW_F_SME 0x20000000 /* source = me */
#define IP_FW_F_DME 0x40000000 /* destination = me */
#define IP_FW_F_MASK 0x7FFFFFFF /* All possible flag bits mask */
/*
* Flags for the 'fw_ipflg' field, for comparing values of ip and its protocols.