diff options
Diffstat (limited to 'sbin/ipfw/tables.c')
-rw-r--r-- | sbin/ipfw/tables.c | 133 |
1 files changed, 128 insertions, 5 deletions
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 89bc363..5444870 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -31,6 +31,7 @@ #include <string.h> #include <sysexits.h> +#include <net/ethernet.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/ip_fw.h> @@ -53,6 +54,7 @@ static void table_lock(ipfw_obj_header *oh, int lock); static int table_swap(ipfw_obj_header *oh, char *second); static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); static int table_show_info(ipfw_xtable_info *i, void *arg); +static void table_zerocnt(ipfw_obj_header *oh, int ac, char *av[]); static int table_destroy_one(ipfw_xtable_info *i, void *arg); static int table_flush_one(ipfw_xtable_info *i, void *arg); @@ -78,6 +80,7 @@ static int tables_foreach(table_cb_t *f, void *arg, int sort); static struct _s_x tabletypes[] = { { "addr", IPFW_TABLE_ADDR }, { "iface", IPFW_TABLE_INTERFACE }, + { "mac", IPFW_TABLE_MAC2 }, { "number", IPFW_TABLE_NUMBER }, { "flow", IPFW_TABLE_FLOW }, { NULL, 0 } @@ -113,6 +116,7 @@ static struct _s_x tablecmds[] = { { "atomic", TOK_ATOMIC }, { "lock", TOK_LOCK }, { "unlock", TOK_UNLOCK }, + { "zerocnt", TOK_ZEROCNT }, { NULL, 0 } }; @@ -297,6 +301,10 @@ ipfw_table_handler(int ac, char *av[]) ac--; av++; table_lookup(&oh, ac, av); break; + case TOK_ZEROCNT: + ac--; av++; + table_zerocnt(&oh, ac, av); + break; } } @@ -1134,11 +1142,65 @@ table_lookup(ipfw_obj_header *oh, int ac, char *av[]) table_show_entry(&xi, &xtent); } +static int +table_do_zerocnt(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi) +{ + char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; + ipfw_obj_tentry *tent; + uint8_t type; + uint32_t vmask; + + memcpy(xbuf, oh, sizeof(*oh)); + oh = (ipfw_obj_header *)xbuf; + tent = (ipfw_obj_tentry *)(oh + 1); + + memset(tent, 0, sizeof(*tent)); + tent->head.length = sizeof(*tent); + tent->idx = 1; + + tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); + oh->ntlv.type = type; + + if (do_set3(IP_FW_TABLE_XZEROCNT, &oh->opheader, sizeof(xbuf)) != 0) + return (errno); + + return (0); +} + +static void +table_zerocnt(ipfw_obj_header *oh, int ac, char *av[]) +{ + ipfw_xtable_info xi; + char key[64]; + int error; + + if (ac == 0) + errx(EX_USAGE, "address required"); + + strlcpy(key, *av, sizeof(key)); + + memset(&xi, 0, sizeof(xi)); + error = table_do_zerocnt(oh, key, &xi); + switch (error) { + case 0: + break; + case ESRCH: + errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); + case ENOENT: + errx(EX_UNAVAILABLE, "Entry %s not found", *av); + case ENOTSUP: + errx(EX_UNAVAILABLE, "Table %s algo does not support " + "\"zero_cnt\" method", oh->ntlv.name); + default: + err(EX_OSERR, "getsockopt(IP_FW_TABLE_XZEROCNT)"); + } +} + 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; @@ -1154,6 +1216,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'; @@ -1187,6 +1258,25 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, af = AF_INET; } break; + case IPFW_TABLE_MAC2: { + char *src, *dst; + struct mac_entry *mac; + + dst = arg; + if ((p = strchr(arg, ',')) == NULL) + errx(EX_DATAERR, "bad mac address pair: %s", arg); + *p = '\0'; + src = p + 1; + + mac = (struct mac_entry *)&tentry->k.mac; + get_mac_addr_mask(dst, mac->addr, mac->mask); /* dst */ + get_mac_addr_mask(src, &(mac->addr[ETHER_ADDR_LEN]), + &(mac->mask[ETHER_ADDR_LEN])); /* src */ + + masklen = ETHER_ADDR_LEN * 8; + af = AF_LINK; + } + break; case IPFW_TABLE_INTERFACE: /* Assume interface name. Copy significant data only */ mask = MIN(strlen(arg), IF_NAMESIZE - 1); @@ -1816,6 +1906,26 @@ table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, } static void +print_mac(uint8_t *addr, uint8_t *mask) +{ + int l; + + l = contigmask(mask, 48); + if (l == 0) + printf(" any"); + else { + printf(" %02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + if (l == -1) + printf("&%02x:%02x:%02x:%02x:%02x:%02x", + mask[0], mask[1], mask[2], + mask[3], mask[4], mask[5]); + else if (l < 48) + printf("/%d", l); + } +} + +static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) { char *comma, tbuf[128], pval[128]; @@ -1829,15 +1939,26 @@ 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\n", 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 */ + print_mac(tent->k.mac.addr, tent->k.mac.mask); + print_mac(tent->k.mac.addr + 6, tent->k.mac.mask + 6); + printf(" %s", pval); break; case IPFW_TABLE_INTERFACE: /* Interface names */ - printf("%s %s\n", tent->k.iface, pval); + printf("%s %s", tent->k.iface, pval); break; case IPFW_TABLE_NUMBER: /* numbers */ - printf("%u %s\n", tent->k.key, pval); + printf("%u %s", tent->k.key, pval); break; case IPFW_TABLE_FLOW: /* flows */ @@ -1880,8 +2001,10 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) comma = ","; } - printf(" %s\n", pval); + printf(" %s", pval); } + printf(" %ju %ju %ju\n", (uintmax_t)tent->pcnt, + (uintmax_t)tent->bcnt, (uintmax_t)tent->timestamp); } static int |