From edfbe4e11e3f835451d36dfb533e0785f4437497 Mon Sep 17 00:00:00 2001 From: Luiz Souza Date: Thu, 20 Jul 2017 14:40:04 -0500 Subject: 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. --- sbin/ipfw/tables.c | 18 ++++++++++-- sys/netpfil/ipfw/ip_fw2.c | 18 ++++++++---- sys/netpfil/ipfw/ip_fw_private.h | 4 +-- sys/netpfil/ipfw/ip_fw_table.c | 5 ++-- sys/netpfil/ipfw/ip_fw_table.h | 1 + sys/netpfil/ipfw/ip_fw_table_algo.c | 58 +++++++++++++++++++++++-------------- sys/netpfil/ipfw/nat64/nat64stl.c | 8 ++--- 7 files changed, 76 insertions(+), 36 deletions(-) diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 862a975..fc0baa0 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -1198,7 +1198,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; @@ -1214,6 +1214,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'; @@ -1928,7 +1937,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); -- cgit v1.1