summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2017-07-20 14:40:04 -0500
committerLuiz Souza <luiz@netgate.com>2017-07-20 16:32:59 -0500
commit178fdf1f95107c227227818b9cc5102fb0e5f3e9 (patch)
tree287c578e8fc1193613c8a7c50c085ef0ecdef235
parentd3d66c182d1ee0a2417d4c816caee778427c279b (diff)
downloadFreeBSD-src-178fdf1f95107c227227818b9cc5102fb0e5f3e9.zip
FreeBSD-src-178fdf1f95107c227227818b9cc5102fb0e5f3e9.tar.gz
Add support for the classic pfSense 'mixed' tables.
The mixed tables are used to match against the IP[4|6] and the MAC address of the peer. (cherry picked from commit edfbe4e11e3f835451d36dfb533e0785f4437497)
-rw-r--r--sbin/ipfw/tables.c18
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c18
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h4
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c5
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.h1
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_algo.c58
-rw-r--r--sys/netpfil/ipfw/nat64/nat64stl.c8
7 files changed, 76 insertions, 36 deletions
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index 21287da..27bb47a 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -1172,7 +1172,7 @@ static void
tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
uint8_t tflags)
{
- char *p, *pp;
+ char *mac, *p, *pp;
int mask, af;
struct in6_addr *paddr, tmp;
struct tflow_entry *tfe;
@@ -1188,6 +1188,15 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
switch (type) {
case IPFW_TABLE_ADDR:
+ /* Remove the ',' if exists */
+ if ((p = strchr(arg, ',')) != NULL) {
+ *p = '\0';
+ mac = p + 1;
+ if (ether_aton_r(mac,
+ (struct ether_addr *)&tentry->mac) == NULL)
+ errx(EX_DATAERR, "bad MAC address: %s", mac);
+ }
+
/* Remove / if exists */
if ((p = strchr(arg, '/')) != NULL) {
*p = '\0';
@@ -1905,7 +1914,12 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
case IPFW_TABLE_ADDR:
/* IPv4 or IPv6 prefixes */
inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
- printf("%s/%u %s", tbuf, tent->masklen, pval);
+ if (tent->mac != 0) {
+ printf("%s/%u", tbuf, tent->masklen);
+ ether_ntoa_r((struct ether_addr *)&tent->mac, tbuf);
+ printf(" %s %s", tbuf, pval);
+ } else
+ printf("%s/%u %s", tbuf, tent->masklen, pval);
break;
case IPFW_TABLE_MAC2:
/* Ethernet MAC address */
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 1d37643..b812e77 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -383,7 +383,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain,
if (cmd->name[0] != '\0') { /* match by name */
if (cmd->name[0] == '\1') /* use tablearg to match */
return ipfw_lookup_table(chain, cmd->p.kidx, 0,
- &ifp->if_index, tablearg, te);
+ &ifp->if_index, tablearg, NULL, te);
/* Check name */
if (cmd->p.glob) {
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -1307,11 +1307,13 @@ do { \
uint32_t tablearg = 0;
int l, cmdlen, skip_or; /* skip rest of OR block */
struct ip_fw *f;
+ uint8_t *ea;
f = chain->map[f_pos];
if (V_set_disable & (1 << f->set) )
continue;
+ ea = NULL;
te = NULL;
tidx = 0;
tkeylen = 0;
@@ -1414,7 +1416,8 @@ do { \
if (args->eh != NULL) { /* have MAC header */
uint32_t v = 0;
match = ipfw_lookup_table(chain,
- cmd->arg1, 0, args->eh, &v, &te);
+ cmd->arg1, 0, args->eh, &v, NULL,
+ &te);
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
if (match) {
@@ -1567,9 +1570,11 @@ do { \
#endif /* !USERSPACE */
else
break;
+ if (args->eh != NULL) /* have MAC header */
+ ea = (uint8_t *)args->eh->ether_dhost;
match = ipfw_lookup_table(chain,
cmd->arg1, keylen, pkey, &vidx,
- &te);
+ ea, &te);
if (!match)
break;
tablearg = vidx;
@@ -1600,8 +1605,10 @@ do { \
pkey = &args->f_id.src_ip6;
} else
break;
+ if (args->eh != NULL) /* have MAC header */
+ ea = (uint8_t *)args->eh->ether_shost;
match = ipfw_lookup_table(chain, cmd->arg1,
- keylen, pkey, &vidx, &te);
+ keylen, pkey, &vidx, ea, &te);
if (!match)
break;
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
@@ -1620,7 +1627,8 @@ do { \
{
uint32_t v = 0;
match = ipfw_lookup_table(chain,
- cmd->arg1, 0, &args->f_id, &v, &te);
+ cmd->arg1, 0, &args->f_id, &v,
+ NULL, &te);
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = ((ipfw_insn_u32 *)cmd)->d[0] ==
TARG_VAL(chain, v, tag);
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index 73523f5..9973aef 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -735,10 +735,10 @@ int ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args,
struct table_info;
typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, void **te);
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
- void *paddr, uint32_t *val, void **te);
+ void *paddr, uint32_t *val, uint8_t *ea, void **te);
void ipfw_cnt_update_tentry(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
void *e, int pktlen);
struct named_object *ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch,
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 8c9f777..395dcc3 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -1089,6 +1089,7 @@ manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
ptei = tei_buf;
ptent = tent;
for (i = 0; i < ctlv->count; i++, ptent++, ptei++) {
+ ptei->mac = ptent->mac;
ptei->paddr = &ptent->k;
ptei->subtype = ptent->subtype;
ptei->masklen = ptent->masklen;
@@ -1725,13 +1726,13 @@ ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx)
*/
int
ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
- void *paddr, uint32_t *val, void **te)
+ void *paddr, uint32_t *val, uint8_t *ea, void **te)
{
struct table_info *ti;
ti = KIDX_TO_TI(ch, tbl);
- return (ti->lookup(ti, paddr, plen, val, te));
+ return (ti->lookup(ti, paddr, plen, val, ea, te));
}
/*
diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h
index 5adb488..cf0309c 100644
--- a/sys/netpfil/ipfw/ip_fw_table.h
+++ b/sys/netpfil/ipfw/ip_fw_table.h
@@ -62,6 +62,7 @@ struct tentry_info {
uint8_t subtype;
uint16_t flags; /* record flags */
uint32_t value; /* value index */
+ uint64_t mac;
};
#define TEI_FLAGS_UPDATE 0x0001 /* Add or update rec if exists */
#define TEI_FLAGS_UPDATED 0x0002 /* Entry has been updated */
diff --git a/sys/netpfil/ipfw/ip_fw_table_algo.c b/sys/netpfil/ipfw/ip_fw_table_algo.c
index dab6640..3dcde55 100644
--- a/sys/netpfil/ipfw/ip_fw_table_algo.c
+++ b/sys/netpfil/ipfw/ip_fw_table_algo.c
@@ -331,6 +331,7 @@ struct radix_addr_entry {
struct sockaddr_in addr;
uint32_t value;
uint64_t bcnt;
+ uint64_t mac;
uint64_t pcnt;
time_t timestamp;
uint8_t masklen;
@@ -348,6 +349,7 @@ struct radix_addr_xentry {
struct sa_in6 addr6;
uint32_t value;
uint64_t bcnt;
+ uint64_t mac;
uint64_t pcnt;
time_t timestamp;
uint8_t masklen;
@@ -378,7 +380,7 @@ struct ta_buf_radix
};
static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, uint8_t *ea, void **te);
static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static int flush_radix_entry(struct radix_node *rn, void *arg);
@@ -412,7 +414,7 @@ static int ta_zero_cnt_radix_tentry(void *ta_state, struct table_info *ti,
static int
ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct radix_node_head *rnh;
@@ -424,6 +426,11 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
rnh = (struct radix_node_head *)ti->state;
ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
if (ent != NULL) {
+ if (ent->mac != 0 && ea == NULL)
+ return (0);
+ if (ent->mac != 0 &&
+ memcmp(ea, &ent->mac, ETHER_ADDR_LEN) != 0)
+ return (0);
*val = ent->value;
if (te != NULL)
*te = (void *)ent;
@@ -437,6 +444,11 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
rnh = (struct radix_node_head *)ti->xstate;
xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
if (xent != NULL) {
+ if (xent->mac != 0 && ea == NULL)
+ return (0);
+ if (xent->mac != 0 &&
+ memcmp(ea, &xent->mac, ETHER_ADDR_LEN) != 0)
+ return (0);
*val = xent->value;
if (te != NULL)
*te = (void *)xent;
@@ -539,6 +551,7 @@ ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
tent->masklen = n->masklen;
tent->subtype = AF_INET;
tent->v.kidx = n->value;
+ tent->mac = n->mac;
tent->bcnt = n->bcnt;
tent->pcnt = n->pcnt;
tent->timestamp = n->timestamp;
@@ -549,6 +562,7 @@ ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
tent->masklen = xn->masklen;
tent->subtype = AF_INET6;
tent->v.kidx = xn->value;
+ tent->mac = n->mac;
tent->bcnt = n->bcnt;
tent->pcnt = n->pcnt;
tent->timestamp = n->timestamp;
@@ -739,9 +753,11 @@ ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
/* Save current entry value from @tei */
if (tei->subtype == AF_INET) {
rnh = ti->state;
+ ((struct radix_addr_entry *)tb->ent_ptr)->mac = tei->mac;
((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value;
} else {
rnh = ti->xstate;
+ ((struct radix_addr_xentry *)tb->ent_ptr)->mac = tei->mac;
((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value;
}
@@ -1034,11 +1050,11 @@ static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask
int hsize);
#endif
static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, void **te);
static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
- uint32_t keylen, uint32_t *val, void **te);
+ uint32_t keylen, uint32_t *val, uint8_t *ea, void **te);
static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, void **te);
static int chash_parse_opts(struct chash_cfg *cfg, char *data);
static void ta_print_chash_config(void *ta_state, struct table_info *ti,
char *buf, size_t bufsize);
@@ -1139,7 +1155,7 @@ hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
static int
ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1188,7 +1204,7 @@ ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
static int
ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1241,7 +1257,7 @@ ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
static int
ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -2124,7 +2140,7 @@ struct ta_buf_ifidx
int compare_ifidx(const void *k, const void *v);
static struct ifidx * ifidx_find(struct table_info *ti, void *key);
static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, void **te);
static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
@@ -2270,7 +2286,7 @@ ifidx_find(struct table_info *ti, void *key)
static int
ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct ifidx *ifi;
@@ -2895,7 +2911,7 @@ struct ta_buf_numarray
int compare_numarray(const void *k, const void *v);
static struct numarray *numarray_find(struct table_info *ti, void *key);
static int ta_lookup_numarray(struct table_info *ti, void *key,
- uint32_t keylen, uint32_t *val, void **te);
+ uint32_t keylen, uint32_t *val, uint8_t *ea, void **te);
static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
@@ -2958,7 +2974,7 @@ numarray_find(struct table_info *ti, void *key)
static int
ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct numarray *ri;
@@ -3406,7 +3422,7 @@ static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, void **te);
static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
@@ -3496,7 +3512,7 @@ hash_flow_ent(struct fhashentry *ent, uint32_t size)
static int
ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct fhashbhead *head;
struct fhashentry *ent;
@@ -4151,7 +4167,7 @@ struct table_algo flow_hash = {
*/
static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te);
+ uint32_t *val, uint8_t *ea, void **te);
static int kfib_parse_opts(int *pfib, char *data);
static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
char *buf, size_t bufsize);
@@ -4173,7 +4189,7 @@ static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
static int
ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
#ifdef INET
struct nhop4_basic nh4;
@@ -4506,7 +4522,7 @@ ta_print_mhash_config(void *ta_state, struct table_info *ti, char *buf,
static __inline int
ta_lookup_find_mhash(struct mhashbhead *head, uint32_t hash2,
- struct macdata *mac, uint32_t *val, void **te)
+ struct macdata *mac, uint32_t *val, uint8_t *ea, void **te)
{
struct macdata any;
struct mhashentry *ent;
@@ -4527,7 +4543,7 @@ ta_lookup_find_mhash(struct mhashbhead *head, uint32_t hash2,
static int
ta_lookup_mhash(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val, void **te)
+ uint32_t *val, uint8_t *ea, void **te)
{
struct macdata mac;
struct mhashbhead *head;
@@ -4541,21 +4557,21 @@ ta_lookup_mhash(struct table_info *ti, void *key, uint32_t keylen,
hsize = 1 << (ti->data & 0xFF);
hash2 = hash_mac2(key, hsize);
if (ta_lookup_find_mhash(head, hash2,
- (struct macdata *)key, val, te) == 1)
+ (struct macdata *)key, val, NULL, te) == 1)
return (1);
/* src any */
memcpy(mac.addr, key, 6);
memset(mac.addr + 6, 0, 6);
hash2 = hash_mac2(mac.addr, hsize);
- if (ta_lookup_find_mhash(head, hash2, &mac, val, te) == 1)
+ if (ta_lookup_find_mhash(head, hash2, &mac, val, NULL, te) == 1)
return (1);
/* dst any */
memset(mac.addr, 0, 6);
memcpy(mac.addr + 6, (uintptr_t *)key + 6, 6);
hash2 = hash_mac2(mac.addr, hsize);
- if (ta_lookup_find_mhash(head, hash2, &mac, val, te) == 1)
+ if (ta_lookup_find_mhash(head, hash2, &mac, val, NULL, te) == 1)
return (1);
return (0);
diff --git a/sys/netpfil/ipfw/nat64/nat64stl.c b/sys/netpfil/ipfw/nat64/nat64stl.c
index a1c34ef..f12a9a6 100644
--- a/sys/netpfil/ipfw/nat64/nat64stl.c
+++ b/sys/netpfil/ipfw/nat64/nat64stl.c
@@ -184,8 +184,8 @@ nat64stl_handle_icmp6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
* IPv4 mapped address.
*/
ip6i = mtodo(m, hlen);
- if (ipfw_lookup_table(chain, cfg->map64,
- sizeof(struct in6_addr), &ip6i->ip6_dst, &tablearg, NULL) == 0) {
+ if (ipfw_lookup_table(chain, cfg->map64, sizeof(struct in6_addr),
+ &ip6i->ip6_dst, &tablearg, NULL, NULL) == 0) {
m_freem(m);
return (NAT64RETURN);
}
@@ -222,12 +222,12 @@ ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_args *args,
case 4:
dst4 = htonl(args->f_id.dst_ip);
ret = ipfw_lookup_table(chain, cfg->map46, sizeof(in_addr_t),
- &dst4, &tablearg, NULL);
+ &dst4, &tablearg, NULL, NULL);
break;
case 6:
ret = ipfw_lookup_table(chain, cfg->map64,
sizeof(struct in6_addr), &args->f_id.src_ip6,
- &tablearg, NULL);
+ &tablearg, NULL, NULL);
break;
default:
return (0);
OpenPOWER on IntegriCloud