1f1220db8SAlexander V. Chernikov /* 21a33e799SAlexander V. Chernikov * Copyright (c) 2014 Yandex LLC 31a33e799SAlexander V. Chernikov * Copyright (c) 2014 Alexander V. Chernikov 4f1220db8SAlexander V. Chernikov * 5f1220db8SAlexander V. Chernikov * Redistribution and use in source forms, with and without modification, 6f1220db8SAlexander V. Chernikov * are permitted provided that this entire comment appears intact. 7f1220db8SAlexander V. Chernikov * 8f1220db8SAlexander V. Chernikov * Redistribution in binary form may occur without any restrictions. 9f1220db8SAlexander V. Chernikov * Obviously, it would be nice if you gave credit where credit is due 10f1220db8SAlexander V. Chernikov * but requiring it would be too onerous. 11f1220db8SAlexander V. Chernikov * 12f1220db8SAlexander V. Chernikov * This software is provided ``AS IS'' without any warranties of any kind. 13f1220db8SAlexander V. Chernikov * 141a33e799SAlexander V. Chernikov * in-kernel ipfw tables support. 15f1220db8SAlexander V. Chernikov * 169fe15d06SAlexander V. Chernikov * $FreeBSD$ 17f1220db8SAlexander V. Chernikov */ 18f1220db8SAlexander V. Chernikov 19f1220db8SAlexander V. Chernikov 20f1220db8SAlexander V. Chernikov #include <sys/types.h> 21f1220db8SAlexander V. Chernikov #include <sys/param.h> 22f1220db8SAlexander V. Chernikov #include <sys/socket.h> 23f1220db8SAlexander V. Chernikov #include <sys/sysctl.h> 24f1220db8SAlexander V. Chernikov 25f1220db8SAlexander V. Chernikov #include <ctype.h> 26f1220db8SAlexander V. Chernikov #include <err.h> 27f1220db8SAlexander V. Chernikov #include <errno.h> 28f1220db8SAlexander V. Chernikov #include <netdb.h> 29f1220db8SAlexander V. Chernikov #include <stdio.h> 30f1220db8SAlexander V. Chernikov #include <stdlib.h> 31f1220db8SAlexander V. Chernikov #include <string.h> 32f1220db8SAlexander V. Chernikov #include <sysexits.h> 33f1220db8SAlexander V. Chernikov 3481cac390SArseny Smalyuk #include <net/ethernet.h> 35f1220db8SAlexander V. Chernikov #include <net/if.h> 36f1220db8SAlexander V. Chernikov #include <netinet/in.h> 37f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h> 38f1220db8SAlexander V. Chernikov #include <arpa/inet.h> 392530ed9eSAndrey V. Elsukov #include <netdb.h> 40f1220db8SAlexander V. Chernikov 41f1220db8SAlexander V. Chernikov #include "ipfw2.h" 42f1220db8SAlexander V. Chernikov 43ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 443a845e10SAlexander V. Chernikov int add, int quiet, int update, int atomic); 45ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh); 46ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh); 47ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 48adf3b2b9SAlexander V. Chernikov static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i); 4946d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second); 50adf3b2b9SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 51adf3b2b9SAlexander V. Chernikov static void table_modify(ipfw_obj_header *oh, int ac, char *av[]); 52adf3b2b9SAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 534f43138aSAlexander V. Chernikov static void table_lock(ipfw_obj_header *oh, int lock); 5446d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second); 55ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 56f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 57f1220db8SAlexander V. Chernikov 58421c5838SAndrey V. Elsukov static int table_destroy_one(ipfw_xtable_info *i, void *arg); 59f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 60f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 61720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); 62f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 6381d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 64f1220db8SAlexander V. Chernikov 65ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 660cba2b28SAlexander V. Chernikov char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi); 67ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 680cba2b28SAlexander V. Chernikov char *arg, uint8_t type, uint32_t vmask); 690cba2b28SAlexander V. Chernikov static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 700cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip); 71ac35ff17SAlexander V. Chernikov 72f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 73f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 74f1220db8SAlexander V. Chernikov 75f1220db8SAlexander V. Chernikov #ifndef s6_addr32 76f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 77f1220db8SAlexander V. Chernikov #endif 78f1220db8SAlexander V. Chernikov 79ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 80c21034b7SAlexander V. Chernikov { "addr", IPFW_TABLE_ADDR }, 8181cac390SArseny Smalyuk { "mac", IPFW_TABLE_MAC }, 82ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 83b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 84914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 85ac35ff17SAlexander V. Chernikov { NULL, 0 } 86ac35ff17SAlexander V. Chernikov }; 87ac35ff17SAlexander V. Chernikov 8813ad237aSAndrey V. Elsukov /* Default algorithms for various table types */ 8913ad237aSAndrey V. Elsukov static struct _s_x tablealgos[] = { 9013ad237aSAndrey V. Elsukov { "addr:radix", IPFW_TABLE_ADDR }, 9113ad237aSAndrey V. Elsukov { "flow:hash", IPFW_TABLE_FLOW }, 9213ad237aSAndrey V. Elsukov { "iface:array", IPFW_TABLE_INTERFACE }, 9313ad237aSAndrey V. Elsukov { "number:array", IPFW_TABLE_NUMBER }, 9413ad237aSAndrey V. Elsukov { NULL, 0 } 9513ad237aSAndrey V. Elsukov }; 9613ad237aSAndrey V. Elsukov 97ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 980cba2b28SAlexander V. Chernikov { "skipto", IPFW_VTYPE_SKIPTO }, 990cba2b28SAlexander V. Chernikov { "pipe", IPFW_VTYPE_PIPE }, 1000cba2b28SAlexander V. Chernikov { "fib", IPFW_VTYPE_FIB }, 1010cba2b28SAlexander V. Chernikov { "nat", IPFW_VTYPE_NAT }, 1020cba2b28SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 1030cba2b28SAlexander V. Chernikov { "tag", IPFW_VTYPE_TAG }, 1040cba2b28SAlexander V. Chernikov { "divert", IPFW_VTYPE_DIVERT }, 1050cba2b28SAlexander V. Chernikov { "netgraph", IPFW_VTYPE_NETGRAPH }, 1060cba2b28SAlexander V. Chernikov { "limit", IPFW_VTYPE_LIMIT }, 1070cba2b28SAlexander V. Chernikov { "ipv4", IPFW_VTYPE_NH4 }, 1080cba2b28SAlexander V. Chernikov { "ipv6", IPFW_VTYPE_NH6 }, 109adf3b2b9SAlexander V. Chernikov { NULL, 0 } 110adf3b2b9SAlexander V. Chernikov }; 111adf3b2b9SAlexander V. Chernikov 112ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 113ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 114ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 11546d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 116ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 117ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 118adf3b2b9SAlexander V. Chernikov { "modify", TOK_MODIFY }, 11946d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 120ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 121358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 122ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 12381d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 1243a845e10SAlexander V. Chernikov { "atomic", TOK_ATOMIC }, 1254f43138aSAlexander V. Chernikov { "lock", TOK_LOCK }, 1264f43138aSAlexander V. Chernikov { "unlock", TOK_UNLOCK }, 127ac35ff17SAlexander V. Chernikov { NULL, 0 } 128ac35ff17SAlexander V. Chernikov }; 129ac35ff17SAlexander V. Chernikov 130f1220db8SAlexander V. Chernikov static int 131f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 132f1220db8SAlexander V. Chernikov { 133f1220db8SAlexander V. Chernikov struct hostent *he; 134f1220db8SAlexander V. Chernikov 135f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 136f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 137f1220db8SAlexander V. Chernikov return(-1); 138f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 139f1220db8SAlexander V. Chernikov } 140f1220db8SAlexander V. Chernikov return(0); 141f1220db8SAlexander V. Chernikov } 142f1220db8SAlexander V. Chernikov 143f1220db8SAlexander V. Chernikov /* 144f1220db8SAlexander V. Chernikov * This one handles all table-related commands 145ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 146be695df9SAlexander V. Chernikov * ipfw table NAME modify ... 147421c5838SAndrey V. Elsukov * ipfw table {NAME | all} destroy 148be695df9SAlexander V. Chernikov * ipfw table NAME swap NAME 149be695df9SAlexander V. Chernikov * ipfw table NAME lock 150be695df9SAlexander V. Chernikov * ipfw table NAME unlock 151ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 152be695df9SAlexander V. Chernikov * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] .. 153be695df9SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] [addr[/masklen]] .. 154be695df9SAlexander V. Chernikov * ipfw table NAME lookup addr 155ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 156ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 157ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 158be695df9SAlexander V. Chernikov * ipfw table {NAME | all} detail 159f1220db8SAlexander V. Chernikov */ 160f1220db8SAlexander V. Chernikov void 161f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 162f1220db8SAlexander V. Chernikov { 163ac35ff17SAlexander V. Chernikov int do_add, is_all; 1643a845e10SAlexander V. Chernikov int atomic, error, tcmd; 165ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 166ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 167f1220db8SAlexander V. Chernikov char *tablename; 168d8caf56eSAndrey V. Elsukov uint8_t set; 169358b9d09SAlexander V. Chernikov void *arg; 170f1220db8SAlexander V. Chernikov 171ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 172ac35ff17SAlexander V. Chernikov is_all = 0; 17356707beeSMark Johnston if (g_co.use_set != 0) 17456707beeSMark Johnston set = g_co.use_set - 1; 175ac35ff17SAlexander V. Chernikov else 176ac35ff17SAlexander V. Chernikov set = 0; 177f1220db8SAlexander V. Chernikov 178f1220db8SAlexander V. Chernikov ac--; av++; 1799d099b4fSAlexander V. Chernikov NEED1("table needs name"); 180f1220db8SAlexander V. Chernikov tablename = *av; 181f1220db8SAlexander V. Chernikov 182ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 183ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 184ac35ff17SAlexander V. Chernikov oh.idx = 1; 185ac35ff17SAlexander V. Chernikov } else { 186ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 187ac35ff17SAlexander V. Chernikov is_all = 1; 188ac35ff17SAlexander V. Chernikov else 189ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 190ac35ff17SAlexander V. Chernikov } 191ac35ff17SAlexander V. Chernikov ac--; av++; 1929d099b4fSAlexander V. Chernikov NEED1("table needs command"); 193ac35ff17SAlexander V. Chernikov 194be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 1953a845e10SAlexander V. Chernikov /* Check if atomic operation was requested */ 1963a845e10SAlexander V. Chernikov atomic = 0; 1973a845e10SAlexander V. Chernikov if (tcmd == TOK_ATOMIC) { 1983a845e10SAlexander V. Chernikov ac--; av++; 1993a845e10SAlexander V. Chernikov NEED1("atomic needs command"); 200be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 2013a845e10SAlexander V. Chernikov switch (tcmd) { 2023a845e10SAlexander V. Chernikov case TOK_ADD: 2033a845e10SAlexander V. Chernikov break; 2043a845e10SAlexander V. Chernikov default: 2053a845e10SAlexander V. Chernikov errx(EX_USAGE, "atomic is not compatible with %s", *av); 2063a845e10SAlexander V. Chernikov } 2073a845e10SAlexander V. Chernikov atomic = 1; 2083a845e10SAlexander V. Chernikov } 209ac35ff17SAlexander V. Chernikov 210ac35ff17SAlexander V. Chernikov switch (tcmd) { 211ac35ff17SAlexander V. Chernikov case TOK_LIST: 212ac35ff17SAlexander V. Chernikov case TOK_INFO: 213358b9d09SAlexander V. Chernikov case TOK_DETAIL: 214ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 215421c5838SAndrey V. Elsukov case TOK_DESTROY: 216ac35ff17SAlexander V. Chernikov break; 217ac35ff17SAlexander V. Chernikov default: 218ac35ff17SAlexander V. Chernikov if (is_all != 0) 219ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 220ac35ff17SAlexander V. Chernikov } 221ac35ff17SAlexander V. Chernikov 222ac35ff17SAlexander V. Chernikov switch (tcmd) { 223ac35ff17SAlexander V. Chernikov case TOK_ADD: 224ac35ff17SAlexander V. Chernikov case TOK_DEL: 225f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 226f1220db8SAlexander V. Chernikov ac--; av++; 22756707beeSMark Johnston table_modify_record(&oh, ac, av, do_add, g_co.do_quiet, 22856707beeSMark Johnston g_co.do_quiet, atomic); 229ac35ff17SAlexander V. Chernikov break; 230ac35ff17SAlexander V. Chernikov case TOK_CREATE: 231f1220db8SAlexander V. Chernikov ac--; av++; 232ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 233ac35ff17SAlexander V. Chernikov break; 234adf3b2b9SAlexander V. Chernikov case TOK_MODIFY: 235adf3b2b9SAlexander V. Chernikov ac--; av++; 236adf3b2b9SAlexander V. Chernikov table_modify(&oh, ac, av); 237adf3b2b9SAlexander V. Chernikov break; 238ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 239421c5838SAndrey V. Elsukov if (is_all == 0) { 24076d03257SAndrey V. Elsukov if (table_destroy(&oh) == 0) 24176d03257SAndrey V. Elsukov break; 24276d03257SAndrey V. Elsukov if (errno != ESRCH) 243421c5838SAndrey V. Elsukov err(EX_OSERR, "failed to destroy table %s", 244421c5838SAndrey V. Elsukov tablename); 24576d03257SAndrey V. Elsukov /* ESRCH isn't fatal, warn if not quiet mode */ 24656707beeSMark Johnston if (g_co.do_quiet == 0) 24776d03257SAndrey V. Elsukov warn("failed to destroy table %s", tablename); 248421c5838SAndrey V. Elsukov } else { 249421c5838SAndrey V. Elsukov error = tables_foreach(table_destroy_one, &oh, 1); 250421c5838SAndrey V. Elsukov if (error != 0) 251421c5838SAndrey V. Elsukov err(EX_OSERR, 252421c5838SAndrey V. Elsukov "failed to destroy tables list"); 253421c5838SAndrey V. Elsukov } 254ac35ff17SAlexander V. Chernikov break; 255ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 256f1220db8SAlexander V. Chernikov if (is_all == 0) { 25776d03257SAndrey V. Elsukov if ((error = table_flush(&oh)) == 0) 25876d03257SAndrey V. Elsukov break; 25976d03257SAndrey V. Elsukov if (errno != ESRCH) 260f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 261f1220db8SAlexander V. Chernikov tablename); 26276d03257SAndrey V. Elsukov /* ESRCH isn't fatal, warn if not quiet mode */ 26356707beeSMark Johnston if (g_co.do_quiet == 0) 26476d03257SAndrey V. Elsukov warn("failed to flush table %s info", 26576d03257SAndrey V. Elsukov tablename); 266f1220db8SAlexander V. Chernikov } else { 267ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 268f1220db8SAlexander V. Chernikov if (error != 0) 269f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 27076d03257SAndrey V. Elsukov /* XXX: we ignore errors here */ 271f1220db8SAlexander V. Chernikov } 272ac35ff17SAlexander V. Chernikov break; 27346d52008SAlexander V. Chernikov case TOK_SWAP: 27446d52008SAlexander V. Chernikov ac--; av++; 27546d52008SAlexander V. Chernikov NEED1("second table name required"); 27646d52008SAlexander V. Chernikov table_swap(&oh, *av); 27746d52008SAlexander V. Chernikov break; 2784f43138aSAlexander V. Chernikov case TOK_LOCK: 2794f43138aSAlexander V. Chernikov case TOK_UNLOCK: 2804f43138aSAlexander V. Chernikov table_lock(&oh, (tcmd == TOK_LOCK)); 2814f43138aSAlexander V. Chernikov break; 282358b9d09SAlexander V. Chernikov case TOK_DETAIL: 283ac35ff17SAlexander V. Chernikov case TOK_INFO: 284358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 285f1220db8SAlexander V. Chernikov if (is_all == 0) { 286ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 287f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 288358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 289f1220db8SAlexander V. Chernikov } else { 290358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 291f1220db8SAlexander V. Chernikov if (error != 0) 292f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 293f1220db8SAlexander V. Chernikov } 294ac35ff17SAlexander V. Chernikov break; 295ac35ff17SAlexander V. Chernikov case TOK_LIST: 29610e3bebfSBryan Drewery arg = is_all ? (void*)1 : NULL; 297ac35ff17SAlexander V. Chernikov if (is_all == 0) { 298ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 299ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 3002b3d6647SBryan Drewery table_show_one(&i, arg); 301f1220db8SAlexander V. Chernikov } else { 3022b3d6647SBryan Drewery error = tables_foreach(table_show_one, arg, 1); 303ac35ff17SAlexander V. Chernikov if (error != 0) 304ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 305f1220db8SAlexander V. Chernikov } 306ac35ff17SAlexander V. Chernikov break; 30781d3153dSAlexander V. Chernikov case TOK_LOOKUP: 30881d3153dSAlexander V. Chernikov ac--; av++; 30981d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 31081d3153dSAlexander V. Chernikov break; 311f1220db8SAlexander V. Chernikov } 312f1220db8SAlexander V. Chernikov } 313f1220db8SAlexander V. Chernikov 314d8caf56eSAndrey V. Elsukov void 315d8caf56eSAndrey V. Elsukov table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set, 3162acdf79fSAndrey V. Elsukov uint16_t uidx) 317f1220db8SAlexander V. Chernikov { 318f1220db8SAlexander V. Chernikov 319563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 320f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 321f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 322ac35ff17SAlexander V. Chernikov ntlv->set = set; 323f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 324f1220db8SAlexander V. Chernikov } 325f1220db8SAlexander V. Chernikov 326f1220db8SAlexander V. Chernikov static void 327f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 328f1220db8SAlexander V. Chernikov { 329f1220db8SAlexander V. Chernikov 330f1220db8SAlexander V. Chernikov oh->idx = 1; 33181d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 332ac35ff17SAlexander V. Chernikov } 333ac35ff17SAlexander V. Chernikov 334ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 335ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 336ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 337ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 3384c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 3394f43138aSAlexander V. Chernikov { "locked", TOK_LOCK }, 34005ab1ef6SAndrey V. Elsukov { "missing", TOK_MISSING }, 34105ab1ef6SAndrey V. Elsukov { "or-flush", TOK_ORFLUSH }, 342ac35ff17SAlexander V. Chernikov { NULL, 0 } 343ac35ff17SAlexander V. Chernikov }; 344ac35ff17SAlexander V. Chernikov 345914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 346914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 347914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 348914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 349914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 350914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 351914bffb6SAlexander V. Chernikov { NULL, 0 } 352914bffb6SAlexander V. Chernikov }; 353914bffb6SAlexander V. Chernikov 35456707beeSMark Johnston static int 355914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 356914bffb6SAlexander V. Chernikov { 3570cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 3580cba2b28SAlexander V. Chernikov char *e; 359914bffb6SAlexander V. Chernikov 360914bffb6SAlexander V. Chernikov /* Parse type options */ 361914bffb6SAlexander V. Chernikov switch(ttype) { 362914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 363914bffb6SAlexander V. Chernikov fset = fclear = 0; 3640cba2b28SAlexander V. Chernikov if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0) 3650cba2b28SAlexander V. Chernikov errx(EX_USAGE, 3660cba2b28SAlexander V. Chernikov "unable to parse flow option %s", e); 367914bffb6SAlexander V. Chernikov *tflags = fset; 368914bffb6SAlexander V. Chernikov break; 369914bffb6SAlexander V. Chernikov default: 370914bffb6SAlexander V. Chernikov return (EX_USAGE); 371914bffb6SAlexander V. Chernikov } 372914bffb6SAlexander V. Chernikov 373914bffb6SAlexander V. Chernikov return (0); 374914bffb6SAlexander V. Chernikov } 375914bffb6SAlexander V. Chernikov 37656707beeSMark Johnston static void 377914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 378914bffb6SAlexander V. Chernikov { 379914bffb6SAlexander V. Chernikov const char *tname; 380914bffb6SAlexander V. Chernikov int l; 381914bffb6SAlexander V. Chernikov 382914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 383914bffb6SAlexander V. Chernikov tname = "unknown"; 384914bffb6SAlexander V. Chernikov 385914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 386914bffb6SAlexander V. Chernikov tbuf += l; 387914bffb6SAlexander V. Chernikov size -= l; 388914bffb6SAlexander V. Chernikov 389914bffb6SAlexander V. Chernikov switch(type) { 390914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 391914bffb6SAlexander V. Chernikov if (tflags != 0) { 392914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 393914bffb6SAlexander V. Chernikov l--; 394914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 395914bffb6SAlexander V. Chernikov } 396914bffb6SAlexander V. Chernikov break; 397914bffb6SAlexander V. Chernikov } 398914bffb6SAlexander V. Chernikov } 399914bffb6SAlexander V. Chernikov 400ac35ff17SAlexander V. Chernikov /* 401ac35ff17SAlexander V. Chernikov * Creates new table 402ac35ff17SAlexander V. Chernikov * 403c21034b7SAlexander V. Chernikov * ipfw table NAME create [ type { addr | iface | number | flow } ] 40405ab1ef6SAndrey V. Elsukov * [ algo algoname ] [missing] [or-flush] 405ac35ff17SAlexander V. Chernikov */ 406ac35ff17SAlexander V. Chernikov static void 407ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 408ac35ff17SAlexander V. Chernikov { 40905ab1ef6SAndrey V. Elsukov ipfw_xtable_info xi, xie; 41005ab1ef6SAndrey V. Elsukov int error, missing, orflush, tcmd, val; 4110cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 4120cba2b28SAlexander V. Chernikov char *e, *p; 413ac35ff17SAlexander V. Chernikov char tbuf[128]; 414ac35ff17SAlexander V. Chernikov 41505ab1ef6SAndrey V. Elsukov missing = orflush = 0; 416ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 417ac35ff17SAlexander V. Chernikov while (ac > 0) { 418be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 419ac35ff17SAlexander V. Chernikov ac--; av++; 420ac35ff17SAlexander V. Chernikov 421ac35ff17SAlexander V. Chernikov switch (tcmd) { 4224c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 4234c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 4244c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 4254c0c07a5SAlexander V. Chernikov ac--; av++; 4264c0c07a5SAlexander V. Chernikov break; 427ac35ff17SAlexander V. Chernikov case TOK_TYPE: 428ac35ff17SAlexander V. Chernikov NEED1("table type required"); 429914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 430914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 431914bffb6SAlexander V. Chernikov *p++ = '\0'; 432ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 433914bffb6SAlexander V. Chernikov if (val == -1) { 434914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 435914bffb6SAlexander V. Chernikov ", "); 436914bffb6SAlexander V. Chernikov errx(EX_USAGE, 437914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 438ac35ff17SAlexander V. Chernikov *av, tbuf); 439914bffb6SAlexander V. Chernikov } 440914bffb6SAlexander V. Chernikov xi.type = val; 441914bffb6SAlexander V. Chernikov if (p != NULL) { 442914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 443914bffb6SAlexander V. Chernikov if (error != 0) 444914bffb6SAlexander V. Chernikov errx(EX_USAGE, 445914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 446914bffb6SAlexander V. Chernikov } 447914bffb6SAlexander V. Chernikov ac--; av++; 448ac35ff17SAlexander V. Chernikov break; 449ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 450ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 4510cba2b28SAlexander V. Chernikov fset = fclear = 0; 4520cba2b28SAlexander V. Chernikov val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear); 453ac35ff17SAlexander V. Chernikov if (val != -1) { 4540cba2b28SAlexander V. Chernikov xi.vmask = fset; 455ac35ff17SAlexander V. Chernikov ac--; av++; 456ac35ff17SAlexander V. Chernikov break; 457ac35ff17SAlexander V. Chernikov } 458ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 459ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 4600cba2b28SAlexander V. Chernikov e, tbuf); 461adf3b2b9SAlexander V. Chernikov break; 462ac35ff17SAlexander V. Chernikov case TOK_ALGO: 463ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 464ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 465ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 466ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 467ac35ff17SAlexander V. Chernikov ac--; av++; 468ac35ff17SAlexander V. Chernikov break; 4694f43138aSAlexander V. Chernikov case TOK_LOCK: 4704f43138aSAlexander V. Chernikov xi.flags |= IPFW_TGFLAGS_LOCKED; 4714f43138aSAlexander V. Chernikov break; 47205ab1ef6SAndrey V. Elsukov case TOK_ORFLUSH: 47305ab1ef6SAndrey V. Elsukov orflush = 1; 47405ab1ef6SAndrey V. Elsukov /* FALLTHROUGH */ 47505ab1ef6SAndrey V. Elsukov case TOK_MISSING: 47605ab1ef6SAndrey V. Elsukov missing = 1; 47705ab1ef6SAndrey V. Elsukov break; 478ac35ff17SAlexander V. Chernikov } 479ac35ff17SAlexander V. Chernikov } 480ac35ff17SAlexander V. Chernikov 481463a577bSEitan Adler /* Set some defaults to preserve compatibility. */ 48213ad237aSAndrey V. Elsukov if (xi.algoname[0] == '\0') { 48313ad237aSAndrey V. Elsukov const char *algo; 48413ad237aSAndrey V. Elsukov 48513ad237aSAndrey V. Elsukov if (xi.type == 0) 486c21034b7SAlexander V. Chernikov xi.type = IPFW_TABLE_ADDR; 48713ad237aSAndrey V. Elsukov algo = match_value(tablealgos, xi.type); 48813ad237aSAndrey V. Elsukov if (algo != NULL) 48913ad237aSAndrey V. Elsukov strlcpy(xi.algoname, algo, sizeof(xi.algoname)); 49013ad237aSAndrey V. Elsukov } 4910cba2b28SAlexander V. Chernikov if (xi.vmask == 0) 4920cba2b28SAlexander V. Chernikov xi.vmask = IPFW_VTYPE_LEGACY; 493fd0869d5SAlexander V. Chernikov 49405ab1ef6SAndrey V. Elsukov error = table_do_create(oh, &xi); 49505ab1ef6SAndrey V. Elsukov 49605ab1ef6SAndrey V. Elsukov if (error == 0) 49705ab1ef6SAndrey V. Elsukov return; 49805ab1ef6SAndrey V. Elsukov 49905ab1ef6SAndrey V. Elsukov if (errno != EEXIST || missing == 0) 500ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 50105ab1ef6SAndrey V. Elsukov 50205ab1ef6SAndrey V. Elsukov /* Check that existing table is the same we are trying to create */ 50305ab1ef6SAndrey V. Elsukov if (table_get_info(oh, &xie) != 0) 50405ab1ef6SAndrey V. Elsukov err(EX_OSERR, "Existing table check failed"); 50505ab1ef6SAndrey V. Elsukov 50605ab1ef6SAndrey V. Elsukov if (xi.limit != xie.limit || xi.type != xie.type || 50705ab1ef6SAndrey V. Elsukov xi.tflags != xie.tflags || xi.vmask != xie.vmask || ( 50805ab1ef6SAndrey V. Elsukov xi.algoname[0] != '\0' && strcmp(xi.algoname, 50905ab1ef6SAndrey V. Elsukov xie.algoname) != 0) || xi.flags != xie.flags) 51005ab1ef6SAndrey V. Elsukov errx(EX_DATAERR, "The existing table is not compatible " 51105ab1ef6SAndrey V. Elsukov "with one you are creating."); 51205ab1ef6SAndrey V. Elsukov 51305ab1ef6SAndrey V. Elsukov /* Flush existing table if instructed to do so */ 51405ab1ef6SAndrey V. Elsukov if (orflush != 0 && table_flush(oh) != 0) 51505ab1ef6SAndrey V. Elsukov err(EX_OSERR, "Table flush on creation failed"); 516f1220db8SAlexander V. Chernikov } 517f1220db8SAlexander V. Chernikov 518f1220db8SAlexander V. Chernikov /* 519ac35ff17SAlexander V. Chernikov * Creates new table 520ac35ff17SAlexander V. Chernikov * 521ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 522ac35ff17SAlexander V. Chernikov * 523f1220db8SAlexander V. Chernikov * Returns 0 on success. 524f1220db8SAlexander V. Chernikov */ 525f1220db8SAlexander V. Chernikov static int 526ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 527f1220db8SAlexander V. Chernikov { 528ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 529ac35ff17SAlexander V. Chernikov int error; 530f1220db8SAlexander V. Chernikov 531ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 532ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 533ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 534ac35ff17SAlexander V. Chernikov 535ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 536ac35ff17SAlexander V. Chernikov 537ac35ff17SAlexander V. Chernikov return (error); 538ac35ff17SAlexander V. Chernikov } 539ac35ff17SAlexander V. Chernikov 540ac35ff17SAlexander V. Chernikov /* 541adf3b2b9SAlexander V. Chernikov * Modifies existing table 542adf3b2b9SAlexander V. Chernikov * 5430cba2b28SAlexander V. Chernikov * ipfw table NAME modify [ limit number ] 544adf3b2b9SAlexander V. Chernikov */ 545adf3b2b9SAlexander V. Chernikov static void 546adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[]) 547adf3b2b9SAlexander V. Chernikov { 548adf3b2b9SAlexander V. Chernikov ipfw_xtable_info xi; 549b6462881SAlexander V. Chernikov int tcmd; 550adf3b2b9SAlexander V. Chernikov 551adf3b2b9SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 552adf3b2b9SAlexander V. Chernikov 553adf3b2b9SAlexander V. Chernikov while (ac > 0) { 554be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 555adf3b2b9SAlexander V. Chernikov ac--; av++; 556adf3b2b9SAlexander V. Chernikov 557adf3b2b9SAlexander V. Chernikov switch (tcmd) { 558adf3b2b9SAlexander V. Chernikov case TOK_LIMIT: 559adf3b2b9SAlexander V. Chernikov NEED1("limit value required"); 560adf3b2b9SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 561adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LIMIT; 562adf3b2b9SAlexander V. Chernikov ac--; av++; 563adf3b2b9SAlexander V. Chernikov break; 5640cba2b28SAlexander V. Chernikov default: 5656ef82c0aSAlan Somers errx(EX_USAGE, "cmd is not supported for modification"); 566adf3b2b9SAlexander V. Chernikov } 567adf3b2b9SAlexander V. Chernikov } 568adf3b2b9SAlexander V. Chernikov 569b6462881SAlexander V. Chernikov if (table_do_modify(oh, &xi) != 0) 570adf3b2b9SAlexander V. Chernikov err(EX_OSERR, "Table modification failed"); 571adf3b2b9SAlexander V. Chernikov } 572adf3b2b9SAlexander V. Chernikov 573adf3b2b9SAlexander V. Chernikov /* 574adf3b2b9SAlexander V. Chernikov * Modifies existing table. 575adf3b2b9SAlexander V. Chernikov * 576adf3b2b9SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 577adf3b2b9SAlexander V. Chernikov * 578adf3b2b9SAlexander V. Chernikov * Returns 0 on success. 579adf3b2b9SAlexander V. Chernikov */ 580adf3b2b9SAlexander V. Chernikov static int 581adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 582adf3b2b9SAlexander V. Chernikov { 583adf3b2b9SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 584adf3b2b9SAlexander V. Chernikov int error; 585adf3b2b9SAlexander V. Chernikov 586adf3b2b9SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 587adf3b2b9SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 588adf3b2b9SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 589adf3b2b9SAlexander V. Chernikov 590adf3b2b9SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 591adf3b2b9SAlexander V. Chernikov 592adf3b2b9SAlexander V. Chernikov return (error); 593adf3b2b9SAlexander V. Chernikov } 5944f43138aSAlexander V. Chernikov 5954f43138aSAlexander V. Chernikov /* 5964f43138aSAlexander V. Chernikov * Locks or unlocks given table 5974f43138aSAlexander V. Chernikov */ 5984f43138aSAlexander V. Chernikov static void 5994f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock) 6004f43138aSAlexander V. Chernikov { 6014f43138aSAlexander V. Chernikov ipfw_xtable_info xi; 6024f43138aSAlexander V. Chernikov 6034f43138aSAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 6044f43138aSAlexander V. Chernikov 6054f43138aSAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LOCK; 6064f43138aSAlexander V. Chernikov xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; 6074f43138aSAlexander V. Chernikov 608b6462881SAlexander V. Chernikov if (table_do_modify(oh, &xi) != 0) 6094f43138aSAlexander V. Chernikov err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); 6104f43138aSAlexander V. Chernikov } 6114f43138aSAlexander V. Chernikov 612adf3b2b9SAlexander V. Chernikov /* 613ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 614ac35ff17SAlexander V. Chernikov * Returns 0 on success. 615ac35ff17SAlexander V. Chernikov */ 616ac35ff17SAlexander V. Chernikov static int 617ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 618ac35ff17SAlexander V. Chernikov { 619ac35ff17SAlexander V. Chernikov 620ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 621f1220db8SAlexander V. Chernikov return (-1); 622f1220db8SAlexander V. Chernikov 623f1220db8SAlexander V. Chernikov return (0); 624f1220db8SAlexander V. Chernikov } 625f1220db8SAlexander V. Chernikov 626421c5838SAndrey V. Elsukov static int 627421c5838SAndrey V. Elsukov table_destroy_one(ipfw_xtable_info *i, void *arg) 628421c5838SAndrey V. Elsukov { 629421c5838SAndrey V. Elsukov ipfw_obj_header *oh; 630421c5838SAndrey V. Elsukov 631421c5838SAndrey V. Elsukov oh = (ipfw_obj_header *)arg; 632421c5838SAndrey V. Elsukov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 633421c5838SAndrey V. Elsukov if (table_destroy(oh) != 0) { 63456707beeSMark Johnston if (g_co.do_quiet == 0) 635421c5838SAndrey V. Elsukov warn("failed to destroy table(%s) in set %u", 636421c5838SAndrey V. Elsukov i->tablename, i->set); 637421c5838SAndrey V. Elsukov return (-1); 638421c5838SAndrey V. Elsukov } 639421c5838SAndrey V. Elsukov return (0); 640421c5838SAndrey V. Elsukov } 641421c5838SAndrey V. Elsukov 642f1220db8SAlexander V. Chernikov /* 643ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 644f1220db8SAlexander V. Chernikov * Returns 0 on success. 645f1220db8SAlexander V. Chernikov */ 646f1220db8SAlexander V. Chernikov static int 647ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 648f1220db8SAlexander V. Chernikov { 649f1220db8SAlexander V. Chernikov 650ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 651f1220db8SAlexander V. Chernikov return (-1); 652f1220db8SAlexander V. Chernikov 653f1220db8SAlexander V. Chernikov return (0); 654f1220db8SAlexander V. Chernikov } 655f1220db8SAlexander V. Chernikov 65646d52008SAlexander V. Chernikov static int 65746d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 65846d52008SAlexander V. Chernikov { 65946d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 66046d52008SAlexander V. Chernikov int error; 66146d52008SAlexander V. Chernikov 66246d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 66346d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 66446d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 66546d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 66646d52008SAlexander V. Chernikov 66746d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 66846d52008SAlexander V. Chernikov 66946d52008SAlexander V. Chernikov return (error); 67046d52008SAlexander V. Chernikov } 67146d52008SAlexander V. Chernikov 67246d52008SAlexander V. Chernikov /* 67346d52008SAlexander V. Chernikov * Swaps given table with @second one. 67446d52008SAlexander V. Chernikov */ 67546d52008SAlexander V. Chernikov static int 67646d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 67746d52008SAlexander V. Chernikov { 67846d52008SAlexander V. Chernikov 67946d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 68046d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 68146d52008SAlexander V. Chernikov 68276d03257SAndrey V. Elsukov if (table_do_swap(oh, second) == 0) 68376d03257SAndrey V. Elsukov return (0); 68446d52008SAlexander V. Chernikov 68576d03257SAndrey V. Elsukov switch (errno) { 68646d52008SAlexander V. Chernikov case EINVAL: 68746d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 68846d52008SAlexander V. Chernikov case EFBIG: 68946d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 69046d52008SAlexander V. Chernikov } 69146d52008SAlexander V. Chernikov 69246d52008SAlexander V. Chernikov return (0); 69346d52008SAlexander V. Chernikov } 69446d52008SAlexander V. Chernikov 69546d52008SAlexander V. Chernikov 696f1220db8SAlexander V. Chernikov /* 697ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 698f1220db8SAlexander V. Chernikov * it inside @i. 699f1220db8SAlexander V. Chernikov * Returns 0 on success. 700f1220db8SAlexander V. Chernikov */ 701f1220db8SAlexander V. Chernikov static int 702ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 703f1220db8SAlexander V. Chernikov { 704f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 705f1220db8SAlexander V. Chernikov size_t sz; 706f1220db8SAlexander V. Chernikov 707f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 708f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 709ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 710f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 711f1220db8SAlexander V. Chernikov 712b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0) 713b6462881SAlexander V. Chernikov return (errno); 714f1220db8SAlexander V. Chernikov 715f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 716ac35ff17SAlexander V. Chernikov return (EINVAL); 717f1220db8SAlexander V. Chernikov 718f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 719f1220db8SAlexander V. Chernikov 720f1220db8SAlexander V. Chernikov return (0); 721f1220db8SAlexander V. Chernikov } 722f1220db8SAlexander V. Chernikov 7235f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 7245f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 7255f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 7265f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 7275f379342SAlexander V. Chernikov { NULL, 0 } 7285f379342SAlexander V. Chernikov }; 7295f379342SAlexander V. Chernikov 7305f379342SAlexander V. Chernikov struct ta_cldata { 7315f379342SAlexander V. Chernikov uint8_t taclass; 7325f379342SAlexander V. Chernikov uint8_t spare4; 7335f379342SAlexander V. Chernikov uint16_t itemsize; 7345f379342SAlexander V. Chernikov uint16_t itemsize6; 7355f379342SAlexander V. Chernikov uint32_t size; 7365f379342SAlexander V. Chernikov uint32_t count; 7375f379342SAlexander V. Chernikov }; 7385f379342SAlexander V. Chernikov 7395f379342SAlexander V. Chernikov /* 7405f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 7415f379342SAlexander V. Chernikov */ 7425f379342SAlexander V. Chernikov static void 74356707beeSMark Johnston table_show_tainfo(ipfw_xtable_info *i __unused, struct ta_cldata *d, 7445f379342SAlexander V. Chernikov const char *af, const char *taclass) 7455f379342SAlexander V. Chernikov { 7465f379342SAlexander V. Chernikov 7475f379342SAlexander V. Chernikov switch (d->taclass) { 7485f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 7495f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 7505f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7515f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7525f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 7535f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 7545f379342SAlexander V. Chernikov else 7555f379342SAlexander V. Chernikov printf(" size: %u items: %u " 7565f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7575f379342SAlexander V. Chernikov d->size, d->count, 7585f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 7595f379342SAlexander V. Chernikov break; 7605f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 7615f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7625f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7635f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 7645f379342SAlexander V. Chernikov d->count, d->itemsize); 7655f379342SAlexander V. Chernikov else 7665f379342SAlexander V. Chernikov printf(" items: %u " 7675f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7685f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 7695f379342SAlexander V. Chernikov break; 7705f379342SAlexander V. Chernikov default: 7715f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 7725f379342SAlexander V. Chernikov } 7735f379342SAlexander V. Chernikov } 7745f379342SAlexander V. Chernikov 7750cba2b28SAlexander V. Chernikov static void 7760cba2b28SAlexander V. Chernikov table_print_valheader(char *buf, size_t bufsize, uint32_t vmask) 7770cba2b28SAlexander V. Chernikov { 7780cba2b28SAlexander V. Chernikov 7790cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 7800cba2b28SAlexander V. Chernikov snprintf(buf, bufsize, "legacy"); 7810cba2b28SAlexander V. Chernikov return; 7820cba2b28SAlexander V. Chernikov } 7830cba2b28SAlexander V. Chernikov 7848a6dbb64SAlexander V. Chernikov memset(buf, 0, bufsize); 7850cba2b28SAlexander V. Chernikov print_flags_buffer(buf, bufsize, tablevaltypes, vmask); 7860cba2b28SAlexander V. Chernikov } 7870cba2b28SAlexander V. Chernikov 788f1220db8SAlexander V. Chernikov /* 789f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 790f1220db8SAlexander V. Chernikov */ 791f1220db8SAlexander V. Chernikov static int 792f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 793f1220db8SAlexander V. Chernikov { 7940cba2b28SAlexander V. Chernikov const char *vtype; 7955f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 7965f379342SAlexander V. Chernikov int afdata, afitem; 7975f379342SAlexander V. Chernikov struct ta_cldata d; 798adf3b2b9SAlexander V. Chernikov char ttype[64], tvtype[64]; 799f1220db8SAlexander V. Chernikov 800914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 8010cba2b28SAlexander V. Chernikov table_print_valheader(tvtype, sizeof(tvtype), i->vmask); 802ac35ff17SAlexander V. Chernikov 803914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 8044f43138aSAlexander V. Chernikov if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) 8054f43138aSAlexander V. Chernikov printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); 8064f43138aSAlexander V. Chernikov else 807914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 8080cba2b28SAlexander V. Chernikov printf(" references: %u, valtype: %s\n", i->refcnt, tvtype); 8099d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 810f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 8114c0c07a5SAlexander V. Chernikov if (i->limit > 0) 8124c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 813f1220db8SAlexander V. Chernikov 814358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 815358b9d09SAlexander V. Chernikov if (arg == NULL) 816358b9d09SAlexander V. Chernikov return (0); 817358b9d09SAlexander V. Chernikov 8185f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 8195f379342SAlexander V. Chernikov return (0); 8205f379342SAlexander V. Chernikov tainfo = &i->ta_info; 8215f379342SAlexander V. Chernikov 8225f379342SAlexander V. Chernikov afdata = 0; 8235f379342SAlexander V. Chernikov afitem = 0; 8245f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 8255f379342SAlexander V. Chernikov afdata = 1; 8265f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 8275f379342SAlexander V. Chernikov afitem = 1; 8285f379342SAlexander V. Chernikov 8295f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 8305f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 8315f379342SAlexander V. Chernikov d.size = tainfo->size4; 8325f379342SAlexander V. Chernikov d.count = tainfo->count4; 8335f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 8345f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 8355f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 8365f379342SAlexander V. Chernikov else 8375f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 8385f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 8395f379342SAlexander V. Chernikov vtype = "unknown"; 8405f379342SAlexander V. Chernikov 8415f379342SAlexander V. Chernikov if (afdata == 0) { 8425f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 8435f379342SAlexander V. Chernikov } else { 8445f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 8455f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 8465f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 8475f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 8485f379342SAlexander V. Chernikov vtype = "unknown"; 8495f379342SAlexander V. Chernikov d.size = tainfo->size6; 8505f379342SAlexander V. Chernikov d.count = tainfo->count6; 8515f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 8525f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 8535f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 8545f379342SAlexander V. Chernikov } 8555f379342SAlexander V. Chernikov 856f1220db8SAlexander V. Chernikov return (0); 857f1220db8SAlexander V. Chernikov } 858f1220db8SAlexander V. Chernikov 859f1220db8SAlexander V. Chernikov 860f1220db8SAlexander V. Chernikov /* 861f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 862f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 863f1220db8SAlexander V. Chernikov */ 864f1220db8SAlexander V. Chernikov 865f1220db8SAlexander V. Chernikov static int 866f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 867f1220db8SAlexander V. Chernikov { 868268a20a0SAdrian Chadd ipfw_obj_header *oh = NULL; 86981d3153dSAlexander V. Chernikov int error; 87010e3bebfSBryan Drewery int is_all; 87110e3bebfSBryan Drewery 87210e3bebfSBryan Drewery is_all = arg == NULL ? 0 : 1; 873f1220db8SAlexander V. Chernikov 874720ee730SAlexander V. Chernikov if ((error = table_do_get_list(i, &oh)) != 0) { 87581d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 87681d3153dSAlexander V. Chernikov return (error); 87781d3153dSAlexander V. Chernikov } 87881d3153dSAlexander V. Chernikov 8792b3d6647SBryan Drewery table_show_list(oh, is_all); 880f1220db8SAlexander V. Chernikov 881f1220db8SAlexander V. Chernikov free(oh); 882f1220db8SAlexander V. Chernikov return (0); 883f1220db8SAlexander V. Chernikov } 884f1220db8SAlexander V. Chernikov 885f1220db8SAlexander V. Chernikov static int 886f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 887f1220db8SAlexander V. Chernikov { 888ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 889f1220db8SAlexander V. Chernikov 890ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 891ac35ff17SAlexander V. Chernikov 892ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 893ac35ff17SAlexander V. Chernikov 894ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 895f1220db8SAlexander V. Chernikov } 896f1220db8SAlexander V. Chernikov 897ac35ff17SAlexander V. Chernikov static int 898ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 8993a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent, int count, int atomic) 900ac35ff17SAlexander V. Chernikov { 901db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 9023a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent_base; 9033a845e10SAlexander V. Chernikov caddr_t pbuf; 904db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 9053a845e10SAlexander V. Chernikov int error, i; 9063a845e10SAlexander V. Chernikov size_t sz; 907ac35ff17SAlexander V. Chernikov 9083a845e10SAlexander V. Chernikov sz = sizeof(*ctlv) + sizeof(*tent) * count; 9093a845e10SAlexander V. Chernikov if (count == 1) { 910ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 9113a845e10SAlexander V. Chernikov pbuf = xbuf; 9123a845e10SAlexander V. Chernikov } else { 9133a845e10SAlexander V. Chernikov if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) 9143a845e10SAlexander V. Chernikov return (ENOMEM); 9153a845e10SAlexander V. Chernikov } 9163a845e10SAlexander V. Chernikov 9173a845e10SAlexander V. Chernikov memcpy(pbuf, oh, sizeof(*oh)); 9183a845e10SAlexander V. Chernikov oh = (ipfw_obj_header *)pbuf; 919ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 920ac35ff17SAlexander V. Chernikov 921db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 9223a845e10SAlexander V. Chernikov ctlv->count = count; 9233a845e10SAlexander V. Chernikov ctlv->head.length = sz; 9243a845e10SAlexander V. Chernikov if (atomic != 0) 9253a845e10SAlexander V. Chernikov ctlv->flags |= IPFW_CTF_ATOMIC; 926db785d31SAlexander V. Chernikov 9273a845e10SAlexander V. Chernikov tent_base = tent; 9283a845e10SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent) * count); 929db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 9303a845e10SAlexander V. Chernikov for (i = 0; i < count; i++, tent++) { 931ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 9323a845e10SAlexander V. Chernikov tent->idx = oh->idx; 9333a845e10SAlexander V. Chernikov } 934ac35ff17SAlexander V. Chernikov 9353a845e10SAlexander V. Chernikov sz += sizeof(*oh); 9363a845e10SAlexander V. Chernikov error = do_get3(cmd, &oh->opheader, &sz); 937092f8ba3SAndrey V. Elsukov if (error != 0) 938092f8ba3SAndrey V. Elsukov error = errno; 9393a845e10SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 9403a845e10SAlexander V. Chernikov /* Copy result back to provided buffer */ 9413a845e10SAlexander V. Chernikov memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); 9423a845e10SAlexander V. Chernikov 9433a845e10SAlexander V. Chernikov if (pbuf != xbuf) 9443a845e10SAlexander V. Chernikov free(pbuf); 945ac35ff17SAlexander V. Chernikov 946ac35ff17SAlexander V. Chernikov return (error); 947ac35ff17SAlexander V. Chernikov } 948ac35ff17SAlexander V. Chernikov 949ac35ff17SAlexander V. Chernikov static void 9503a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, 9513a845e10SAlexander V. Chernikov int quiet, int update, int atomic) 952ac35ff17SAlexander V. Chernikov { 9533a845e10SAlexander V. Chernikov ipfw_obj_tentry *ptent, tent, *tent_buf; 95481d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 95556707beeSMark Johnston const char *etxt, *px, *texterr; 9560cba2b28SAlexander V. Chernikov uint8_t type; 9570cba2b28SAlexander V. Chernikov uint32_t vmask; 9583a845e10SAlexander V. Chernikov int cmd, count, error, i, ignored; 959ac35ff17SAlexander V. Chernikov 960ac35ff17SAlexander V. Chernikov if (ac == 0) 961ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 962ac35ff17SAlexander V. Chernikov 963ac35ff17SAlexander V. Chernikov if (add != 0) { 964ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 9654c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 966ac35ff17SAlexander V. Chernikov } else { 967ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 9684c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 969ac35ff17SAlexander V. Chernikov } 970ac35ff17SAlexander V. Chernikov 9713a845e10SAlexander V. Chernikov /* 9723a845e10SAlexander V. Chernikov * Calculate number of entries: 9733a845e10SAlexander V. Chernikov * Assume [key val] x N for add 9743a845e10SAlexander V. Chernikov * and 9753a845e10SAlexander V. Chernikov * key x N for delete 9763a845e10SAlexander V. Chernikov */ 9773a845e10SAlexander V. Chernikov count = (add != 0) ? ac / 2 + 1 : ac; 9783a845e10SAlexander V. Chernikov 9793a845e10SAlexander V. Chernikov if (count <= 1) { 9803a845e10SAlexander V. Chernikov /* Adding single entry with/without value */ 9813a845e10SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 9823a845e10SAlexander V. Chernikov tent_buf = &tent; 9833a845e10SAlexander V. Chernikov } else { 9843a845e10SAlexander V. Chernikov 9853a845e10SAlexander V. Chernikov if ((tent_buf = calloc(count, sizeof(tent))) == NULL) 9863a845e10SAlexander V. Chernikov errx(EX_OSERR, 9873a845e10SAlexander V. Chernikov "Unable to allocate memory for all entries"); 9883a845e10SAlexander V. Chernikov } 9893a845e10SAlexander V. Chernikov ptent = tent_buf; 9903a845e10SAlexander V. Chernikov 9913a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 9923a845e10SAlexander V. Chernikov count = 0; 9933a845e10SAlexander V. Chernikov while (ac > 0) { 9940cba2b28SAlexander V. Chernikov tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi); 9953a845e10SAlexander V. Chernikov 9963a845e10SAlexander V. Chernikov /* 997463a577bSEitan Adler * Compatibility layer: auto-create table if not exists. 9983a845e10SAlexander V. Chernikov */ 9993a845e10SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 10003a845e10SAlexander V. Chernikov xi.type = type; 10010cba2b28SAlexander V. Chernikov xi.vmask = vmask; 10023a845e10SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, 10033a845e10SAlexander V. Chernikov sizeof(xi.tablename)); 1004e62cd31fSAndrey V. Elsukov if (quiet == 0) 1005e62cd31fSAndrey V. Elsukov warnx("DEPRECATED: inserting data into " 1006e62cd31fSAndrey V. Elsukov "non-existent table %s. (auto-created)", 10073a845e10SAlexander V. Chernikov xi.tablename); 10083a845e10SAlexander V. Chernikov table_do_create(oh, &xi); 10093a845e10SAlexander V. Chernikov } 10103a845e10SAlexander V. Chernikov 10113a845e10SAlexander V. Chernikov oh->ntlv.type = type; 10123a845e10SAlexander V. Chernikov ac--; av++; 10133a845e10SAlexander V. Chernikov 10143a845e10SAlexander V. Chernikov if (add != 0 && ac > 0) { 10150cba2b28SAlexander V. Chernikov tentry_fill_value(oh, ptent, *av, type, vmask); 10163a845e10SAlexander V. Chernikov ac--; av++; 10173a845e10SAlexander V. Chernikov } 10183a845e10SAlexander V. Chernikov 10193a845e10SAlexander V. Chernikov if (update != 0) 10203a845e10SAlexander V. Chernikov ptent->head.flags |= IPFW_TF_UPDATE; 10213a845e10SAlexander V. Chernikov 10223a845e10SAlexander V. Chernikov count++; 10233a845e10SAlexander V. Chernikov ptent++; 10243a845e10SAlexander V. Chernikov } 10253a845e10SAlexander V. Chernikov 10263a845e10SAlexander V. Chernikov error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 10273a845e10SAlexander V. Chernikov 10283a845e10SAlexander V. Chernikov /* 10293a845e10SAlexander V. Chernikov * Compatibility stuff: do not yell on duplicate keys or 10303a845e10SAlexander V. Chernikov * failed deletions. 10313a845e10SAlexander V. Chernikov */ 10323a845e10SAlexander V. Chernikov if (error == 0 || (error == EEXIST && add != 0) || 10333a845e10SAlexander V. Chernikov (error == ENOENT && add == 0)) { 10343a845e10SAlexander V. Chernikov if (quiet != 0) { 10353a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10363a845e10SAlexander V. Chernikov free(tent_buf); 10373a845e10SAlexander V. Chernikov return; 10383a845e10SAlexander V. Chernikov } 10393a845e10SAlexander V. Chernikov } 10403a845e10SAlexander V. Chernikov 10413a845e10SAlexander V. Chernikov /* Report results back */ 10423a845e10SAlexander V. Chernikov ptent = tent_buf; 10433a845e10SAlexander V. Chernikov for (i = 0; i < count; ptent++, i++) { 10443a845e10SAlexander V. Chernikov ignored = 0; 10453a845e10SAlexander V. Chernikov switch (ptent->result) { 10463a845e10SAlexander V. Chernikov case IPFW_TR_ADDED: 10473a845e10SAlexander V. Chernikov px = "added"; 10483a845e10SAlexander V. Chernikov break; 10493a845e10SAlexander V. Chernikov case IPFW_TR_DELETED: 10503a845e10SAlexander V. Chernikov px = "deleted"; 10513a845e10SAlexander V. Chernikov break; 10523a845e10SAlexander V. Chernikov case IPFW_TR_UPDATED: 10533a845e10SAlexander V. Chernikov px = "updated"; 10543a845e10SAlexander V. Chernikov break; 10553a845e10SAlexander V. Chernikov case IPFW_TR_LIMIT: 10563a845e10SAlexander V. Chernikov px = "limit"; 10573a845e10SAlexander V. Chernikov ignored = 1; 10583a845e10SAlexander V. Chernikov break; 10593a845e10SAlexander V. Chernikov case IPFW_TR_ERROR: 10603a845e10SAlexander V. Chernikov px = "error"; 10613a845e10SAlexander V. Chernikov ignored = 1; 10623a845e10SAlexander V. Chernikov break; 10633a845e10SAlexander V. Chernikov case IPFW_TR_NOTFOUND: 10643a845e10SAlexander V. Chernikov px = "notfound"; 10653a845e10SAlexander V. Chernikov ignored = 1; 10663a845e10SAlexander V. Chernikov break; 10673a845e10SAlexander V. Chernikov case IPFW_TR_EXISTS: 10683a845e10SAlexander V. Chernikov px = "exists"; 10693a845e10SAlexander V. Chernikov ignored = 1; 10703a845e10SAlexander V. Chernikov break; 10713a845e10SAlexander V. Chernikov case IPFW_TR_IGNORED: 10723a845e10SAlexander V. Chernikov px = "ignored"; 10733a845e10SAlexander V. Chernikov ignored = 1; 10743a845e10SAlexander V. Chernikov break; 10753a845e10SAlexander V. Chernikov default: 10763a845e10SAlexander V. Chernikov px = "unknown"; 10773a845e10SAlexander V. Chernikov ignored = 1; 10783a845e10SAlexander V. Chernikov } 10793a845e10SAlexander V. Chernikov 10803a845e10SAlexander V. Chernikov if (error != 0 && atomic != 0 && ignored == 0) 10813a845e10SAlexander V. Chernikov printf("%s(reverted): ", px); 10823a845e10SAlexander V. Chernikov else 10833a845e10SAlexander V. Chernikov printf("%s: ", px); 10843a845e10SAlexander V. Chernikov 10853a845e10SAlexander V. Chernikov table_show_entry(&xi, ptent); 10863a845e10SAlexander V. Chernikov } 10873a845e10SAlexander V. Chernikov 10883a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10893a845e10SAlexander V. Chernikov free(tent_buf); 10903a845e10SAlexander V. Chernikov 10913a845e10SAlexander V. Chernikov if (error == 0) 10924c0c07a5SAlexander V. Chernikov return; 109368bde59eSAlexander V. Chernikov /* Get real OS error */ 109468bde59eSAlexander V. Chernikov error = errno; 10954c0c07a5SAlexander V. Chernikov 10964c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 10974c0c07a5SAlexander V. Chernikov switch (error) { 10984c0c07a5SAlexander V. Chernikov case EEXIST: 10994c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 11004c0c07a5SAlexander V. Chernikov break; 11014c0c07a5SAlexander V. Chernikov case EFBIG: 11024c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 11034c0c07a5SAlexander V. Chernikov break; 11044c0c07a5SAlexander V. Chernikov case ESRCH: 11054c0c07a5SAlexander V. Chernikov etxt = "table not found"; 11064c0c07a5SAlexander V. Chernikov break; 11074c0c07a5SAlexander V. Chernikov case ENOENT: 11084c0c07a5SAlexander V. Chernikov etxt = "record not found"; 11094c0c07a5SAlexander V. Chernikov break; 11104f43138aSAlexander V. Chernikov case EACCES: 11114f43138aSAlexander V. Chernikov etxt = "table is locked"; 11124f43138aSAlexander V. Chernikov break; 11134c0c07a5SAlexander V. Chernikov default: 11144c0c07a5SAlexander V. Chernikov etxt = strerror(error); 11154c0c07a5SAlexander V. Chernikov } 11164c0c07a5SAlexander V. Chernikov 11174c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 1118ac35ff17SAlexander V. Chernikov } 1119ac35ff17SAlexander V. Chernikov 112081d3153dSAlexander V. Chernikov static int 112181d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 112281d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 112381d3153dSAlexander V. Chernikov { 112481d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 112581d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 11260cba2b28SAlexander V. Chernikov uint8_t type; 11270cba2b28SAlexander V. Chernikov uint32_t vmask; 112881d3153dSAlexander V. Chernikov size_t sz; 112981d3153dSAlexander V. Chernikov 113081d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 113181d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 113281d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 113381d3153dSAlexander V. Chernikov 113481d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 113581d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 113681d3153dSAlexander V. Chernikov tent->idx = 1; 113781d3153dSAlexander V. Chernikov 11380cba2b28SAlexander V. Chernikov tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); 113981d3153dSAlexander V. Chernikov oh->ntlv.type = type; 114081d3153dSAlexander V. Chernikov 114181d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 1142b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0) 1143b6462881SAlexander V. Chernikov return (errno); 114481d3153dSAlexander V. Chernikov 114581d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 114681d3153dSAlexander V. Chernikov return (EINVAL); 114781d3153dSAlexander V. Chernikov 114881d3153dSAlexander V. Chernikov *xtent = *tent; 114981d3153dSAlexander V. Chernikov 115081d3153dSAlexander V. Chernikov return (0); 115181d3153dSAlexander V. Chernikov } 115281d3153dSAlexander V. Chernikov 115381d3153dSAlexander V. Chernikov static void 115481d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 115581d3153dSAlexander V. Chernikov { 115681d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 115781d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 1158914bffb6SAlexander V. Chernikov char key[64]; 115981d3153dSAlexander V. Chernikov int error; 116081d3153dSAlexander V. Chernikov 116181d3153dSAlexander V. Chernikov if (ac == 0) 116281d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 116381d3153dSAlexander V. Chernikov 1164914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 1165914bffb6SAlexander V. Chernikov 11663a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 1167914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 116881d3153dSAlexander V. Chernikov 116981d3153dSAlexander V. Chernikov switch (error) { 117081d3153dSAlexander V. Chernikov case 0: 117181d3153dSAlexander V. Chernikov break; 117281d3153dSAlexander V. Chernikov case ESRCH: 117381d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 117481d3153dSAlexander V. Chernikov case ENOENT: 117581d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 117681d3153dSAlexander V. Chernikov case ENOTSUP: 117781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 117881d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 117981d3153dSAlexander V. Chernikov default: 118081d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 118181d3153dSAlexander V. Chernikov } 118281d3153dSAlexander V. Chernikov 118381d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 118481d3153dSAlexander V. Chernikov } 1185ac35ff17SAlexander V. Chernikov 1186ac35ff17SAlexander V. Chernikov static void 1187914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1188914bffb6SAlexander V. Chernikov uint8_t tflags) 1189ac35ff17SAlexander V. Chernikov { 1190914bffb6SAlexander V. Chernikov char *p, *pp; 1191ac35ff17SAlexander V. Chernikov int mask, af; 1192914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 119381cac390SArseny Smalyuk struct ether_addr *mac; 1194914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 1195ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 1196914bffb6SAlexander V. Chernikov uint16_t port; 1197914bffb6SAlexander V. Chernikov struct protoent *pent; 1198914bffb6SAlexander V. Chernikov struct servent *sent; 1199ac35ff17SAlexander V. Chernikov int masklen; 1200ac35ff17SAlexander V. Chernikov 1201268a20a0SAdrian Chadd mask = masklen = 0; 1202ac35ff17SAlexander V. Chernikov af = 0; 1203ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 1204ac35ff17SAlexander V. Chernikov 1205ac35ff17SAlexander V. Chernikov switch (type) { 1206c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1207ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 1208ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 1209ac35ff17SAlexander V. Chernikov *p = '\0'; 1210ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 1211ac35ff17SAlexander V. Chernikov } 1212ac35ff17SAlexander V. Chernikov 1213ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 1214ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 1215ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 1216ac35ff17SAlexander V. Chernikov p + 1); 1217ac35ff17SAlexander V. Chernikov 1218ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 1219ac35ff17SAlexander V. Chernikov af = AF_INET; 1220ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 1221ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 1222ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 1223ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 1224ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 1225ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 1226ac35ff17SAlexander V. Chernikov p + 1); 1227ac35ff17SAlexander V. Chernikov 1228ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 1229ac35ff17SAlexander V. Chernikov af = AF_INET6; 1230ac35ff17SAlexander V. Chernikov } else { 1231ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 1232ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1233ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1234ac35ff17SAlexander V. Chernikov 1235ac35ff17SAlexander V. Chernikov masklen = 32; 1236c21034b7SAlexander V. Chernikov type = IPFW_TABLE_ADDR; 1237ac35ff17SAlexander V. Chernikov af = AF_INET; 1238ac35ff17SAlexander V. Chernikov } 1239ac35ff17SAlexander V. Chernikov break; 124081cac390SArseny Smalyuk case IPFW_TABLE_MAC: 124181cac390SArseny Smalyuk /* Remove / if exists */ 124281cac390SArseny Smalyuk if ((p = strchr(arg, '/')) != NULL) { 124381cac390SArseny Smalyuk *p = '\0'; 124481cac390SArseny Smalyuk mask = atoi(p + 1); 124581cac390SArseny Smalyuk } 124681cac390SArseny Smalyuk 124781cac390SArseny Smalyuk if (p != NULL && mask > 8 * ETHER_ADDR_LEN) 124881cac390SArseny Smalyuk errx(EX_DATAERR, "bad MAC mask width: %s", 124981cac390SArseny Smalyuk p + 1); 125081cac390SArseny Smalyuk 125181cac390SArseny Smalyuk if ((mac = ether_aton(arg)) == NULL) 125281cac390SArseny Smalyuk errx(EX_DATAERR, "Incorrect MAC address"); 125381cac390SArseny Smalyuk 125481cac390SArseny Smalyuk memcpy(tentry->k.mac, mac->octet, ETHER_ADDR_LEN); 125581cac390SArseny Smalyuk masklen = p ? mask : 8 * ETHER_ADDR_LEN; 125681cac390SArseny Smalyuk af = AF_LINK; 125781cac390SArseny Smalyuk break; 1258ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1259ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 1260ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1261ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 1262ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 1263ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 1264ac35ff17SAlexander V. Chernikov break; 1265b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1266ac35ff17SAlexander V. Chernikov /* Port or any other key */ 1267ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 1268ac35ff17SAlexander V. Chernikov if (*p != '\0') 1269ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 1270ac35ff17SAlexander V. Chernikov 1271ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 1272ac35ff17SAlexander V. Chernikov *pkey = key; 1273ac35ff17SAlexander V. Chernikov masklen = 32; 1274ac35ff17SAlexander V. Chernikov break; 1275914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1276914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1277914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 1278914bffb6SAlexander V. Chernikov af = 0; 1279914bffb6SAlexander V. Chernikov 1280914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6> */ 1281914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1282914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1283914bffb6SAlexander V. Chernikov *p++ = '\0'; 1284914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1285914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1286914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1287914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1288914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1289914bffb6SAlexander V. Chernikov af = AF_INET; 1290914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 1291914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1292914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1293914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1294914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1295914bffb6SAlexander V. Chernikov af = AF_INET6; 1296914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 1297914bffb6SAlexander V. Chernikov } 1298914bffb6SAlexander V. Chernikov 1299914bffb6SAlexander V. Chernikov arg = p; 1300914bffb6SAlexander V. Chernikov } 1301914bffb6SAlexander V. Chernikov 1302914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 1303914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 130435df97d0SAlexander V. Chernikov if (arg == NULL) 130535df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: proto missing"); 1306914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1307914bffb6SAlexander V. Chernikov *p++ = '\0'; 1308914bffb6SAlexander V. Chernikov 1309914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 1310914bffb6SAlexander V. Chernikov if (*pp != '\0') { 1311914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 1312914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 1313914bffb6SAlexander V. Chernikov arg); 1314914bffb6SAlexander V. Chernikov else 1315914bffb6SAlexander V. Chernikov key = pent->p_proto; 1316914bffb6SAlexander V. Chernikov } 1317914bffb6SAlexander V. Chernikov 1318914bffb6SAlexander V. Chernikov if (key > 255) 1319914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 1320914bffb6SAlexander V. Chernikov 1321914bffb6SAlexander V. Chernikov tfe->proto = key; 1322914bffb6SAlexander V. Chernikov 1323914bffb6SAlexander V. Chernikov arg = p; 1324914bffb6SAlexander V. Chernikov } 1325914bffb6SAlexander V. Chernikov 1326914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1327914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 132835df97d0SAlexander V. Chernikov if (arg == NULL) 132935df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: src port missing"); 1330914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1331914bffb6SAlexander V. Chernikov *p++ = '\0'; 1332914bffb6SAlexander V. Chernikov 133352772a85SAndrey V. Elsukov port = htons(strtol(arg, &pp, 10)); 133452772a85SAndrey V. Elsukov if (*pp != '\0') { 1335914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1336914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1337914bffb6SAlexander V. Chernikov arg); 133852772a85SAndrey V. Elsukov port = sent->s_port; 1339914bffb6SAlexander V. Chernikov } 1340914bffb6SAlexander V. Chernikov tfe->sport = port; 1341914bffb6SAlexander V. Chernikov arg = p; 1342914bffb6SAlexander V. Chernikov } 1343914bffb6SAlexander V. Chernikov 1344914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1345914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 134635df97d0SAlexander V. Chernikov if (arg == NULL) 134735df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst ip missing"); 1348914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1349914bffb6SAlexander V. Chernikov *p++ = '\0'; 1350914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1351914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1352914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1353914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1354914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1355914bffb6SAlexander V. Chernikov af = AF_INET; 1356914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 1357914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1358914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1359914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1360914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1361914bffb6SAlexander V. Chernikov af = AF_INET6; 1362914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1363914bffb6SAlexander V. Chernikov } 1364914bffb6SAlexander V. Chernikov 1365914bffb6SAlexander V. Chernikov arg = p; 1366914bffb6SAlexander V. Chernikov } 1367914bffb6SAlexander V. Chernikov 1368914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1369914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 137035df97d0SAlexander V. Chernikov if (arg == NULL) 137135df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst port missing"); 1372914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1373914bffb6SAlexander V. Chernikov *p++ = '\0'; 1374914bffb6SAlexander V. Chernikov 137552772a85SAndrey V. Elsukov port = htons(strtol(arg, &pp, 10)); 137652772a85SAndrey V. Elsukov if (*pp != '\0') { 1377914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1378914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1379914bffb6SAlexander V. Chernikov arg); 138052772a85SAndrey V. Elsukov port = sent->s_port; 1381914bffb6SAlexander V. Chernikov } 1382914bffb6SAlexander V. Chernikov tfe->dport = port; 1383914bffb6SAlexander V. Chernikov arg = p; 1384914bffb6SAlexander V. Chernikov } 1385914bffb6SAlexander V. Chernikov 1386914bffb6SAlexander V. Chernikov tfe->af = af; 1387914bffb6SAlexander V. Chernikov 1388914bffb6SAlexander V. Chernikov break; 1389914bffb6SAlexander V. Chernikov 1390ac35ff17SAlexander V. Chernikov default: 1391ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1392ac35ff17SAlexander V. Chernikov } 1393ac35ff17SAlexander V. Chernikov 1394ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1395ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1396ac35ff17SAlexander V. Chernikov } 1397ac35ff17SAlexander V. Chernikov 13988755aff6SAlexander V. Chernikov /* 13998755aff6SAlexander V. Chernikov * Tries to guess table key type. 14008755aff6SAlexander V. Chernikov * This procedure is used in legacy table auto-create 14018755aff6SAlexander V. Chernikov * code AND in `ipfw -n` ruleset checking. 14028755aff6SAlexander V. Chernikov * 14038755aff6SAlexander V. Chernikov * Imported from old table_fill_xentry() parse code. 14048755aff6SAlexander V. Chernikov */ 14058755aff6SAlexander V. Chernikov static int 14068755aff6SAlexander V. Chernikov guess_key_type(char *key, uint8_t *ptype) 14078755aff6SAlexander V. Chernikov { 14088755aff6SAlexander V. Chernikov char *p; 14098755aff6SAlexander V. Chernikov struct in6_addr addr; 14108755aff6SAlexander V. Chernikov uint32_t kv; 14118755aff6SAlexander V. Chernikov 14128755aff6SAlexander V. Chernikov if (ishexnumber(*key) != 0 || *key == ':') { 14138755aff6SAlexander V. Chernikov /* Remove / if exists */ 14148755aff6SAlexander V. Chernikov if ((p = strchr(key, '/')) != NULL) 14158755aff6SAlexander V. Chernikov *p = '\0'; 14168755aff6SAlexander V. Chernikov 14178755aff6SAlexander V. Chernikov if ((inet_pton(AF_INET, key, &addr) == 1) || 14188755aff6SAlexander V. Chernikov (inet_pton(AF_INET6, key, &addr) == 1)) { 14198755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 14208755aff6SAlexander V. Chernikov if (p != NULL) 14218755aff6SAlexander V. Chernikov *p = '/'; 14228755aff6SAlexander V. Chernikov return (0); 14238755aff6SAlexander V. Chernikov } else { 14248755aff6SAlexander V. Chernikov /* Port or any other key */ 14258755aff6SAlexander V. Chernikov /* Skip non-base 10 entries like 'fa1' */ 14268755aff6SAlexander V. Chernikov kv = strtol(key, &p, 10); 14278755aff6SAlexander V. Chernikov if (*p == '\0') { 14288755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 14298755aff6SAlexander V. Chernikov return (0); 14308755aff6SAlexander V. Chernikov } else if ((p != key) && (*p == '.')) { 14318755aff6SAlexander V. Chernikov /* 14328755aff6SAlexander V. Chernikov * Warn on IPv4 address strings 14338755aff6SAlexander V. Chernikov * which are "valid" for inet_aton() but not 14348755aff6SAlexander V. Chernikov * in inet_pton(). 14358755aff6SAlexander V. Chernikov * 14368755aff6SAlexander V. Chernikov * Typical examples: '10.5' or '10.0.0.05' 14378755aff6SAlexander V. Chernikov */ 14388755aff6SAlexander V. Chernikov return (1); 14398755aff6SAlexander V. Chernikov } 14408755aff6SAlexander V. Chernikov } 14418755aff6SAlexander V. Chernikov } 14428755aff6SAlexander V. Chernikov 14438755aff6SAlexander V. Chernikov if (strchr(key, '.') == NULL) { 14448755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 14458755aff6SAlexander V. Chernikov return (0); 14468755aff6SAlexander V. Chernikov } 14478755aff6SAlexander V. Chernikov 14488755aff6SAlexander V. Chernikov if (lookup_host(key, (struct in_addr *)&addr) != 0) 14498755aff6SAlexander V. Chernikov return (1); 14508755aff6SAlexander V. Chernikov 14518755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 14528755aff6SAlexander V. Chernikov return (0); 14538755aff6SAlexander V. Chernikov } 14548755aff6SAlexander V. Chernikov 1455ac35ff17SAlexander V. Chernikov static void 1456ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 14570cba2b28SAlexander V. Chernikov int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) 1458ac35ff17SAlexander V. Chernikov { 14590cba2b28SAlexander V. Chernikov uint8_t type, tflags; 14600cba2b28SAlexander V. Chernikov uint32_t vmask; 1461ac35ff17SAlexander V. Chernikov int error; 1462ac35ff17SAlexander V. Chernikov 1463ac35ff17SAlexander V. Chernikov type = 0; 1464914bffb6SAlexander V. Chernikov tflags = 0; 14650cba2b28SAlexander V. Chernikov vmask = 0; 1466ac35ff17SAlexander V. Chernikov 14673a845e10SAlexander V. Chernikov if (xi->tablename[0] == '\0') 146881d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 14693a845e10SAlexander V. Chernikov else 14703a845e10SAlexander V. Chernikov error = 0; 147181d3153dSAlexander V. Chernikov 147281d3153dSAlexander V. Chernikov if (error == 0) { 147356707beeSMark Johnston if (g_co.test_only == 0) { 14748755aff6SAlexander V. Chernikov /* Table found */ 147581d3153dSAlexander V. Chernikov type = xi->type; 1476914bffb6SAlexander V. Chernikov tflags = xi->tflags; 14770cba2b28SAlexander V. Chernikov vmask = xi->vmask; 147881d3153dSAlexander V. Chernikov } else { 14798755aff6SAlexander V. Chernikov /* 1480463a577bSEitan Adler * We're running `ipfw -n` 1481463a577bSEitan Adler * Compatibility layer: try to guess key type 14828755aff6SAlexander V. Chernikov * before failing. 14838755aff6SAlexander V. Chernikov */ 14848755aff6SAlexander V. Chernikov if (guess_key_type(key, &type) != 0) { 14858755aff6SAlexander V. Chernikov /* Inknown key */ 14868755aff6SAlexander V. Chernikov errx(EX_USAGE, "Cannot guess " 14878755aff6SAlexander V. Chernikov "key '%s' type", key); 14888755aff6SAlexander V. Chernikov } 14898755aff6SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 14908755aff6SAlexander V. Chernikov } 14918755aff6SAlexander V. Chernikov } else { 149281d3153dSAlexander V. Chernikov if (error != ESRCH) 149381d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 149481d3153dSAlexander V. Chernikov oh->ntlv.name); 149535df97d0SAlexander V. Chernikov if (add == 0) 149635df97d0SAlexander V. Chernikov errx(EX_DATAERR, "Table %s does not exist", 149735df97d0SAlexander V. Chernikov oh->ntlv.name); 1498ac35ff17SAlexander V. Chernikov /* 14998755aff6SAlexander V. Chernikov * Table does not exist 1500463a577bSEitan Adler * Compatibility layer: try to guess key type before failing. 1501ac35ff17SAlexander V. Chernikov */ 15028755aff6SAlexander V. Chernikov if (guess_key_type(key, &type) != 0) { 150381d3153dSAlexander V. Chernikov /* Inknown key */ 150481d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1505db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 150681d3153dSAlexander V. Chernikov } 15078755aff6SAlexander V. Chernikov 15088755aff6SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 1509ac35ff17SAlexander V. Chernikov } 1510ac35ff17SAlexander V. Chernikov 1511914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1512ac35ff17SAlexander V. Chernikov 1513ac35ff17SAlexander V. Chernikov *ptype = type; 15140cba2b28SAlexander V. Chernikov *pvmask = vmask; 15150cba2b28SAlexander V. Chernikov } 15160cba2b28SAlexander V. Chernikov 15170cba2b28SAlexander V. Chernikov static void 15180cba2b28SAlexander V. Chernikov set_legacy_value(uint32_t val, ipfw_table_value *v) 15190cba2b28SAlexander V. Chernikov { 15200cba2b28SAlexander V. Chernikov v->tag = val; 15210cba2b28SAlexander V. Chernikov v->pipe = val; 15220cba2b28SAlexander V. Chernikov v->divert = val; 15230cba2b28SAlexander V. Chernikov v->skipto = val; 15240cba2b28SAlexander V. Chernikov v->netgraph = val; 15250cba2b28SAlexander V. Chernikov v->fib = val; 15260cba2b28SAlexander V. Chernikov v->nat = val; 15270cba2b28SAlexander V. Chernikov v->nh4 = val; 15280cba2b28SAlexander V. Chernikov v->dscp = (uint8_t)val; 15290cba2b28SAlexander V. Chernikov v->limit = val; 1530ac35ff17SAlexander V. Chernikov } 1531ac35ff17SAlexander V. Chernikov 1532ac35ff17SAlexander V. Chernikov static void 153356707beeSMark Johnston tentry_fill_value(ipfw_obj_header *oh __unused, ipfw_obj_tentry *tent, 153456707beeSMark Johnston char *arg, uint8_t type __unused, uint32_t vmask) 1535ac35ff17SAlexander V. Chernikov { 15362530ed9eSAndrey V. Elsukov struct addrinfo hints, *res; 153756707beeSMark Johnston struct in_addr ipaddr; 153856707beeSMark Johnston const char *etype; 153956707beeSMark Johnston char *comma, *e, *n, *p; 1540b7684f4bSMarcelo Araujo uint32_t a4, flag, val; 15410cba2b28SAlexander V. Chernikov ipfw_table_value *v; 15420cba2b28SAlexander V. Chernikov uint32_t i; 1543d91c61c3SAlexander V. Chernikov int dval; 1544ac35ff17SAlexander V. Chernikov 15450cba2b28SAlexander V. Chernikov v = &tent->v.value; 15460cba2b28SAlexander V. Chernikov 15470cba2b28SAlexander V. Chernikov /* Compat layer: keep old behavior for legacy value types */ 15480cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 1549adf3b2b9SAlexander V. Chernikov /* Try to interpret as number first */ 15500cba2b28SAlexander V. Chernikov val = strtoul(arg, &p, 0); 15510cba2b28SAlexander V. Chernikov if (*p == '\0') { 15520cba2b28SAlexander V. Chernikov set_legacy_value(val, v); 1553adf3b2b9SAlexander V. Chernikov return; 15540cba2b28SAlexander V. Chernikov } 1555adf3b2b9SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &val) == 1) { 15560cba2b28SAlexander V. Chernikov set_legacy_value(ntohl(val), v); 1557adf3b2b9SAlexander V. Chernikov return; 1558adf3b2b9SAlexander V. Chernikov } 1559adf3b2b9SAlexander V. Chernikov /* Try hostname */ 15604e0a8b61SConrad Meyer if (lookup_host(arg, &ipaddr) == 0) { 15614e0a8b61SConrad Meyer set_legacy_value(ntohl(ipaddr.s_addr), v); 1562adf3b2b9SAlexander V. Chernikov return; 15630cba2b28SAlexander V. Chernikov } 1564adf3b2b9SAlexander V. Chernikov errx(EX_OSERR, "Unable to parse value %s", arg); 15650cba2b28SAlexander V. Chernikov } 15660cba2b28SAlexander V. Chernikov 15670cba2b28SAlexander V. Chernikov /* 15680cba2b28SAlexander V. Chernikov * Shorthands: handle single value if vmask consists 15690cba2b28SAlexander V. Chernikov * of numbers only. e.g.: 15700cba2b28SAlexander V. Chernikov * vmask = "fib,skipto" -> treat input "1" as "1,1" 15710cba2b28SAlexander V. Chernikov */ 15720cba2b28SAlexander V. Chernikov 15730cba2b28SAlexander V. Chernikov n = arg; 15740cba2b28SAlexander V. Chernikov etype = NULL; 157556707beeSMark Johnston for (i = 1; i < (1u << 31); i *= 2) { 15760cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 15770cba2b28SAlexander V. Chernikov continue; 15780cba2b28SAlexander V. Chernikov vmask &= ~flag; 15790cba2b28SAlexander V. Chernikov 15800cba2b28SAlexander V. Chernikov if ((comma = strchr(n, ',')) != NULL) 15810cba2b28SAlexander V. Chernikov *comma = '\0'; 15820cba2b28SAlexander V. Chernikov 15830cba2b28SAlexander V. Chernikov switch (flag) { 15840cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 15850cba2b28SAlexander V. Chernikov v->tag = strtol(n, &e, 10); 15860cba2b28SAlexander V. Chernikov if (*e != '\0') 15870cba2b28SAlexander V. Chernikov etype = "tag"; 1588ac35ff17SAlexander V. Chernikov break; 15890cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 15900cba2b28SAlexander V. Chernikov v->pipe = strtol(n, &e, 10); 15910cba2b28SAlexander V. Chernikov if (*e != '\0') 15920cba2b28SAlexander V. Chernikov etype = "pipe"; 1593ac35ff17SAlexander V. Chernikov break; 15940cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 15950cba2b28SAlexander V. Chernikov v->divert = strtol(n, &e, 10); 15960cba2b28SAlexander V. Chernikov if (*e != '\0') 15970cba2b28SAlexander V. Chernikov etype = "divert"; 15980cba2b28SAlexander V. Chernikov break; 15990cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 16000cba2b28SAlexander V. Chernikov v->skipto = strtol(n, &e, 10); 16010cba2b28SAlexander V. Chernikov if (*e != '\0') 16020cba2b28SAlexander V. Chernikov etype = "skipto"; 16030cba2b28SAlexander V. Chernikov break; 16040cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 16050cba2b28SAlexander V. Chernikov v->netgraph = strtol(n, &e, 10); 16060cba2b28SAlexander V. Chernikov if (*e != '\0') 16070cba2b28SAlexander V. Chernikov etype = "netgraph"; 16080cba2b28SAlexander V. Chernikov break; 16090cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 16100cba2b28SAlexander V. Chernikov v->fib = strtol(n, &e, 10); 16110cba2b28SAlexander V. Chernikov if (*e != '\0') 16120cba2b28SAlexander V. Chernikov etype = "fib"; 16130cba2b28SAlexander V. Chernikov break; 16140cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 16150cba2b28SAlexander V. Chernikov v->nat = strtol(n, &e, 10); 16160cba2b28SAlexander V. Chernikov if (*e != '\0') 16170cba2b28SAlexander V. Chernikov etype = "nat"; 16180cba2b28SAlexander V. Chernikov break; 16190cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 16200cba2b28SAlexander V. Chernikov v->limit = strtol(n, &e, 10); 16210cba2b28SAlexander V. Chernikov if (*e != '\0') 16220cba2b28SAlexander V. Chernikov etype = "limit"; 16230cba2b28SAlexander V. Chernikov break; 16240cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 16250cba2b28SAlexander V. Chernikov if (strchr(n, '.') != NULL && 16260cba2b28SAlexander V. Chernikov inet_pton(AF_INET, n, &a4) == 1) { 16270cba2b28SAlexander V. Chernikov v->nh4 = ntohl(a4); 16280cba2b28SAlexander V. Chernikov break; 16290cba2b28SAlexander V. Chernikov } 16304e0a8b61SConrad Meyer if (lookup_host(n, &ipaddr) == 0) { 16314e0a8b61SConrad Meyer v->nh4 = ntohl(ipaddr.s_addr); 16320cba2b28SAlexander V. Chernikov break; 16334e0a8b61SConrad Meyer } 16340cba2b28SAlexander V. Chernikov etype = "ipv4"; 1635ac35ff17SAlexander V. Chernikov break; 1636ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 16370cba2b28SAlexander V. Chernikov if (isalpha(*n)) { 1638d91c61c3SAlexander V. Chernikov if ((dval = match_token(f_ipdscp, n)) != -1) { 1639d91c61c3SAlexander V. Chernikov v->dscp = dval; 1640ac35ff17SAlexander V. Chernikov break; 1641d91c61c3SAlexander V. Chernikov } else 16420cba2b28SAlexander V. Chernikov etype = "DSCP code"; 16430cba2b28SAlexander V. Chernikov } else { 16440cba2b28SAlexander V. Chernikov v->dscp = strtol(n, &e, 10); 16450cba2b28SAlexander V. Chernikov if (v->dscp > 63 || *e != '\0') 16460cba2b28SAlexander V. Chernikov etype = "DSCP value"; 1647ac35ff17SAlexander V. Chernikov } 16480cba2b28SAlexander V. Chernikov break; 16490cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 16502530ed9eSAndrey V. Elsukov if (strchr(n, ':') != NULL) { 16512530ed9eSAndrey V. Elsukov memset(&hints, 0, sizeof(hints)); 16522530ed9eSAndrey V. Elsukov hints.ai_family = AF_INET6; 16532530ed9eSAndrey V. Elsukov hints.ai_flags = AI_NUMERICHOST; 16542530ed9eSAndrey V. Elsukov if (getaddrinfo(n, NULL, &hints, &res) == 0) { 16552530ed9eSAndrey V. Elsukov v->nh6 = ((struct sockaddr_in6 *) 16562530ed9eSAndrey V. Elsukov res->ai_addr)->sin6_addr; 16572530ed9eSAndrey V. Elsukov v->zoneid = ((struct sockaddr_in6 *) 16582530ed9eSAndrey V. Elsukov res->ai_addr)->sin6_scope_id; 16592530ed9eSAndrey V. Elsukov freeaddrinfo(res); 16600cba2b28SAlexander V. Chernikov break; 16612530ed9eSAndrey V. Elsukov } 16622530ed9eSAndrey V. Elsukov } 16630cba2b28SAlexander V. Chernikov etype = "ipv6"; 16640cba2b28SAlexander V. Chernikov break; 16650cba2b28SAlexander V. Chernikov } 16660cba2b28SAlexander V. Chernikov 16670cba2b28SAlexander V. Chernikov if (etype != NULL) 16680cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Unable to parse %s as %s", n, etype); 16690cba2b28SAlexander V. Chernikov 16700cba2b28SAlexander V. Chernikov if (comma != NULL) 16710cba2b28SAlexander V. Chernikov *comma++ = ','; 16720cba2b28SAlexander V. Chernikov 16730cba2b28SAlexander V. Chernikov if ((n = comma) != NULL) 16740cba2b28SAlexander V. Chernikov continue; 16750cba2b28SAlexander V. Chernikov 16760cba2b28SAlexander V. Chernikov /* End of input. */ 16770cba2b28SAlexander V. Chernikov if (vmask != 0) 16780cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Not enough fields inside value"); 16790cba2b28SAlexander V. Chernikov } 1680ac35ff17SAlexander V. Chernikov } 1681f1220db8SAlexander V. Chernikov 1682f1220db8SAlexander V. Chernikov /* 1683f1220db8SAlexander V. Chernikov * Compare table names. 1684f1220db8SAlexander V. Chernikov * Honor number comparison. 1685f1220db8SAlexander V. Chernikov */ 1686f1220db8SAlexander V. Chernikov static int 1687f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1688f1220db8SAlexander V. Chernikov { 168956707beeSMark Johnston const ipfw_xtable_info *ia, *ib; 1690f1220db8SAlexander V. Chernikov 169156707beeSMark Johnston ia = (const ipfw_xtable_info *)a; 169256707beeSMark Johnston ib = (const ipfw_xtable_info *)b; 1693f1220db8SAlexander V. Chernikov 169468394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1695f1220db8SAlexander V. Chernikov } 1696f1220db8SAlexander V. Chernikov 1697f1220db8SAlexander V. Chernikov /* 1698f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1699f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1700f1220db8SAlexander V. Chernikov * Returns 0 on success. 1701f1220db8SAlexander V. Chernikov */ 1702f1220db8SAlexander V. Chernikov static int 1703f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1704f1220db8SAlexander V. Chernikov { 170528ea4fa3SAlexander V. Chernikov ipfw_obj_lheader *olh; 1706f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1707f1220db8SAlexander V. Chernikov size_t sz; 170856707beeSMark Johnston uint32_t i; 170956707beeSMark Johnston int error; 1710f1220db8SAlexander V. Chernikov 171128ea4fa3SAlexander V. Chernikov /* Start with reasonable default */ 171228ea4fa3SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1713f1220db8SAlexander V. Chernikov 171428ea4fa3SAlexander V. Chernikov for (;;) { 1715f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1716f1220db8SAlexander V. Chernikov return (ENOMEM); 1717f1220db8SAlexander V. Chernikov 1718f1220db8SAlexander V. Chernikov olh->size = sz; 1719b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) { 172028ea4fa3SAlexander V. Chernikov sz = olh->size; 172168bde59eSAlexander V. Chernikov free(olh); 172268bde59eSAlexander V. Chernikov if (errno != ENOMEM) 1723b6462881SAlexander V. Chernikov return (errno); 172468bde59eSAlexander V. Chernikov continue; 1725f1220db8SAlexander V. Chernikov } 1726f1220db8SAlexander V. Chernikov 1727f1220db8SAlexander V. Chernikov if (sort != 0) 1728e028ccdaSAndrey V. Elsukov qsort(olh + 1, olh->count, olh->objsize, 1729e028ccdaSAndrey V. Elsukov tablename_cmp); 1730f1220db8SAlexander V. Chernikov 1731f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1732f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 173356707beeSMark Johnston if (g_co.use_set == 0 || info->set == g_co.use_set - 1) 1734e028ccdaSAndrey V. Elsukov error = f(info, arg); 1735e028ccdaSAndrey V. Elsukov info = (ipfw_xtable_info *)((caddr_t)info + 1736e028ccdaSAndrey V. Elsukov olh->objsize); 1737f1220db8SAlexander V. Chernikov } 1738f1220db8SAlexander V. Chernikov free(olh); 173928ea4fa3SAlexander V. Chernikov break; 174028ea4fa3SAlexander V. Chernikov } 1741f1220db8SAlexander V. Chernikov return (0); 1742f1220db8SAlexander V. Chernikov } 1743f1220db8SAlexander V. Chernikov 174428ea4fa3SAlexander V. Chernikov 1745f1220db8SAlexander V. Chernikov /* 1746f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1747720ee730SAlexander V. Chernikov * eXtended format. Allocate buffer large enough 1748720ee730SAlexander V. Chernikov * to store result. Called needs to free it later. 1749f1220db8SAlexander V. Chernikov * 1750f1220db8SAlexander V. Chernikov * Returns 0 on success. 1751f1220db8SAlexander V. Chernikov */ 1752f1220db8SAlexander V. Chernikov static int 1753720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1754f1220db8SAlexander V. Chernikov { 1755720ee730SAlexander V. Chernikov ipfw_obj_header *oh; 1756f1220db8SAlexander V. Chernikov size_t sz; 1757b6462881SAlexander V. Chernikov int c; 1758f1220db8SAlexander V. Chernikov 175981d3153dSAlexander V. Chernikov sz = 0; 1760720ee730SAlexander V. Chernikov oh = NULL; 1761720ee730SAlexander V. Chernikov for (c = 0; c < 8; c++) { 176281d3153dSAlexander V. Chernikov if (sz < i->size) 1763720ee730SAlexander V. Chernikov sz = i->size + 44; 1764720ee730SAlexander V. Chernikov if (oh != NULL) 1765720ee730SAlexander V. Chernikov free(oh); 1766720ee730SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1767720ee730SAlexander V. Chernikov continue; 1768720ee730SAlexander V. Chernikov table_fill_objheader(oh, i); 1769d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 1770b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) { 1771720ee730SAlexander V. Chernikov *poh = oh; 1772720ee730SAlexander V. Chernikov return (0); 177381d3153dSAlexander V. Chernikov } 1774f1220db8SAlexander V. Chernikov 1775b6462881SAlexander V. Chernikov if (errno != ENOMEM) 1776720ee730SAlexander V. Chernikov break; 1777720ee730SAlexander V. Chernikov } 1778720ee730SAlexander V. Chernikov free(oh); 1779720ee730SAlexander V. Chernikov 1780b6462881SAlexander V. Chernikov return (errno); 1781f1220db8SAlexander V. Chernikov } 1782f1220db8SAlexander V. Chernikov 1783f1220db8SAlexander V. Chernikov /* 1784f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1785f1220db8SAlexander V. Chernikov */ 1786f1220db8SAlexander V. Chernikov static void 1787f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1788f1220db8SAlexander V. Chernikov { 178981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 179081d3153dSAlexander V. Chernikov uint32_t count; 1791f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1792f1220db8SAlexander V. Chernikov 1793f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 179481d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1795f1220db8SAlexander V. Chernikov 1796f1220db8SAlexander V. Chernikov if (need_header) 1797f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1798f1220db8SAlexander V. Chernikov 1799f1220db8SAlexander V. Chernikov count = i->count; 1800f1220db8SAlexander V. Chernikov while (count > 0) { 180181d3153dSAlexander V. Chernikov table_show_entry(i, tent); 180281d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 180381d3153dSAlexander V. Chernikov count--; 180481d3153dSAlexander V. Chernikov } 180581d3153dSAlexander V. Chernikov } 180681d3153dSAlexander V. Chernikov 180781d3153dSAlexander V. Chernikov static void 18080cba2b28SAlexander V. Chernikov table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 18090cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip) 18100cba2b28SAlexander V. Chernikov { 18112530ed9eSAndrey V. Elsukov char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; 18122530ed9eSAndrey V. Elsukov struct sockaddr_in6 sa6; 18130cba2b28SAlexander V. Chernikov uint32_t flag, i, l; 18140cba2b28SAlexander V. Chernikov size_t sz; 18150cba2b28SAlexander V. Chernikov struct in_addr a4; 18160cba2b28SAlexander V. Chernikov 18170cba2b28SAlexander V. Chernikov sz = bufsize; 18180cba2b28SAlexander V. Chernikov 18190cba2b28SAlexander V. Chernikov /* 18200cba2b28SAlexander V. Chernikov * Some shorthands for printing values: 18210cba2b28SAlexander V. Chernikov * legacy assumes all values are equal, so keep the first one. 18220cba2b28SAlexander V. Chernikov */ 18230cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 18240cba2b28SAlexander V. Chernikov if (print_ip != 0) { 18250cba2b28SAlexander V. Chernikov flag = htonl(v->tag); 18260cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &flag, buf, sz); 18270cba2b28SAlexander V. Chernikov } else 18280cba2b28SAlexander V. Chernikov snprintf(buf, sz, "%u", v->tag); 18290cba2b28SAlexander V. Chernikov return; 18300cba2b28SAlexander V. Chernikov } 18310cba2b28SAlexander V. Chernikov 183256707beeSMark Johnston for (i = 1; i < (1u << 31); i *= 2) { 18330cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 18340cba2b28SAlexander V. Chernikov continue; 18350cba2b28SAlexander V. Chernikov l = 0; 18360cba2b28SAlexander V. Chernikov 18370cba2b28SAlexander V. Chernikov switch (flag) { 18380cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 18390cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->tag); 18400cba2b28SAlexander V. Chernikov break; 18410cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 18420cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->pipe); 18430cba2b28SAlexander V. Chernikov break; 18440cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 18450cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->divert); 18460cba2b28SAlexander V. Chernikov break; 18470cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 18480cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->skipto); 18490cba2b28SAlexander V. Chernikov break; 18500cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 18510cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->netgraph); 18520cba2b28SAlexander V. Chernikov break; 18530cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 18540cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->fib); 18550cba2b28SAlexander V. Chernikov break; 18560cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 18570cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->nat); 18580cba2b28SAlexander V. Chernikov break; 18590cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 18600cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->limit); 18610cba2b28SAlexander V. Chernikov break; 18620cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 18630cba2b28SAlexander V. Chernikov a4.s_addr = htonl(v->nh4); 18640cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); 18650cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 18660cba2b28SAlexander V. Chernikov break; 18670cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 18680cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->dscp); 18690cba2b28SAlexander V. Chernikov break; 18700cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 18712530ed9eSAndrey V. Elsukov sa6.sin6_family = AF_INET6; 18722530ed9eSAndrey V. Elsukov sa6.sin6_len = sizeof(sa6); 18732530ed9eSAndrey V. Elsukov sa6.sin6_addr = v->nh6; 18742530ed9eSAndrey V. Elsukov sa6.sin6_port = 0; 18752530ed9eSAndrey V. Elsukov sa6.sin6_scope_id = v->zoneid; 18762530ed9eSAndrey V. Elsukov if (getnameinfo((const struct sockaddr *)&sa6, 18772530ed9eSAndrey V. Elsukov sa6.sin6_len, abuf, sizeof(abuf), NULL, 0, 18782530ed9eSAndrey V. Elsukov NI_NUMERICHOST) == 0) 18790cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 18800cba2b28SAlexander V. Chernikov break; 18810cba2b28SAlexander V. Chernikov } 18820cba2b28SAlexander V. Chernikov 18830cba2b28SAlexander V. Chernikov buf += l; 18840cba2b28SAlexander V. Chernikov sz -= l; 18850cba2b28SAlexander V. Chernikov } 18860cba2b28SAlexander V. Chernikov 18870cba2b28SAlexander V. Chernikov if (sz != bufsize) 18880cba2b28SAlexander V. Chernikov *(buf - 1) = '\0'; 18890cba2b28SAlexander V. Chernikov } 18900cba2b28SAlexander V. Chernikov 18910cba2b28SAlexander V. Chernikov static void 189281d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 189381d3153dSAlexander V. Chernikov { 189456707beeSMark Johnston char tbuf[128], pval[128]; 189556707beeSMark Johnston const char *comma; 189681cac390SArseny Smalyuk const u_char *mac; 1897914bffb6SAlexander V. Chernikov void *paddr; 1898914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 189981d3153dSAlexander V. Chernikov 19000cba2b28SAlexander V. Chernikov table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, 190156707beeSMark Johnston g_co.do_value_as_ip); 1902914bffb6SAlexander V. Chernikov 1903f1220db8SAlexander V. Chernikov switch (i->type) { 1904c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1905f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 190681d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1907914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1908f1220db8SAlexander V. Chernikov break; 190981cac390SArseny Smalyuk case IPFW_TABLE_MAC: 191081cac390SArseny Smalyuk /* MAC prefixes */ 191181cac390SArseny Smalyuk mac = tent->k.mac; 191281cac390SArseny Smalyuk printf("%02x:%02x:%02x:%02x:%02x:%02x/%u %s\n", 191381cac390SArseny Smalyuk mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], 191481cac390SArseny Smalyuk tent->masklen, pval); 191581cac390SArseny Smalyuk break; 1916f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1917f1220db8SAlexander V. Chernikov /* Interface names */ 1918914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1919b23d5de9SAlexander V. Chernikov break; 1920b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1921b23d5de9SAlexander V. Chernikov /* numbers */ 1922914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1923b23d5de9SAlexander V. Chernikov break; 1924914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1925914bffb6SAlexander V. Chernikov /* flows */ 1926914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1927914bffb6SAlexander V. Chernikov comma = ""; 1928914bffb6SAlexander V. Chernikov 1929914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1930914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1931914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1932914bffb6SAlexander V. Chernikov else 1933914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1934914bffb6SAlexander V. Chernikov 1935914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1936914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1937914bffb6SAlexander V. Chernikov comma = ","; 1938914bffb6SAlexander V. Chernikov } 1939914bffb6SAlexander V. Chernikov 1940914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1941914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1942914bffb6SAlexander V. Chernikov comma = ","; 1943914bffb6SAlexander V. Chernikov } 1944914bffb6SAlexander V. Chernikov 1945914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1946914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1947914bffb6SAlexander V. Chernikov comma = ","; 1948914bffb6SAlexander V. Chernikov } 1949914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1950914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1951914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1952914bffb6SAlexander V. Chernikov else 1953914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1954914bffb6SAlexander V. Chernikov 1955914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1956914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1957914bffb6SAlexander V. Chernikov comma = ","; 1958914bffb6SAlexander V. Chernikov } 1959914bffb6SAlexander V. Chernikov 1960914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1961914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1962914bffb6SAlexander V. Chernikov comma = ","; 1963914bffb6SAlexander V. Chernikov } 1964914bffb6SAlexander V. Chernikov 1965914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1966f1220db8SAlexander V. Chernikov } 1967f1220db8SAlexander V. Chernikov } 1968f1220db8SAlexander V. Chernikov 19699d099b4fSAlexander V. Chernikov static int 19700cba2b28SAlexander V. Chernikov table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) 19719d099b4fSAlexander V. Chernikov { 19729d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 19739d099b4fSAlexander V. Chernikov size_t sz; 19749d099b4fSAlexander V. Chernikov 19759d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 19769d099b4fSAlexander V. Chernikov sz = sizeof(req); 19779d099b4fSAlexander V. Chernikov 1978b6462881SAlexander V. Chernikov if (do_get3(opcode, &req.opheader, &sz) != 0) 1979b6462881SAlexander V. Chernikov if (errno != ENOMEM) 1980b6462881SAlexander V. Chernikov return (errno); 19819d099b4fSAlexander V. Chernikov 19829d099b4fSAlexander V. Chernikov sz = req.size; 19839d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 19849d099b4fSAlexander V. Chernikov return (ENOMEM); 19859d099b4fSAlexander V. Chernikov 19869d099b4fSAlexander V. Chernikov olh->size = sz; 1987b6462881SAlexander V. Chernikov if (do_get3(opcode, &olh->opheader, &sz) != 0) { 19889d099b4fSAlexander V. Chernikov free(olh); 1989b6462881SAlexander V. Chernikov return (errno); 19909d099b4fSAlexander V. Chernikov } 19919d099b4fSAlexander V. Chernikov 19929d099b4fSAlexander V. Chernikov *polh = olh; 19939d099b4fSAlexander V. Chernikov return (0); 19949d099b4fSAlexander V. Chernikov } 19959d099b4fSAlexander V. Chernikov 19960cba2b28SAlexander V. Chernikov static int 19970cba2b28SAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 19980cba2b28SAlexander V. Chernikov { 19990cba2b28SAlexander V. Chernikov 20000cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); 20010cba2b28SAlexander V. Chernikov } 20020cba2b28SAlexander V. Chernikov 20030cba2b28SAlexander V. Chernikov static int 20040cba2b28SAlexander V. Chernikov table_do_get_vlist(ipfw_obj_lheader **polh) 20050cba2b28SAlexander V. Chernikov { 20060cba2b28SAlexander V. Chernikov 20070cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); 20080cba2b28SAlexander V. Chernikov } 20090cba2b28SAlexander V. Chernikov 20109d099b4fSAlexander V. Chernikov void 201156707beeSMark Johnston ipfw_list_ta(int ac __unused, char *av[] __unused) 20129d099b4fSAlexander V. Chernikov { 20139d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 20149d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 20159d099b4fSAlexander V. Chernikov const char *atype; 201656707beeSMark Johnston uint32_t i; 201756707beeSMark Johnston int error; 20189d099b4fSAlexander V. Chernikov 20199d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 20209d099b4fSAlexander V. Chernikov if (error != 0) 20219d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 20229d099b4fSAlexander V. Chernikov 20239d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 20249d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 20259d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 20269d099b4fSAlexander V. Chernikov atype = "unknown"; 20278ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 20288ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 20299d099b4fSAlexander V. Chernikov 20309d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 20319d099b4fSAlexander V. Chernikov } 20329d099b4fSAlexander V. Chernikov 20339d099b4fSAlexander V. Chernikov free(olh); 20349d099b4fSAlexander V. Chernikov } 20359d099b4fSAlexander V. Chernikov 20360cba2b28SAlexander V. Chernikov 20370cba2b28SAlexander V. Chernikov /* Copy of current kernel table_value structure */ 20380cba2b28SAlexander V. Chernikov struct _table_value { 20390cba2b28SAlexander V. Chernikov uint32_t tag; /* O_TAG/O_TAGGED */ 20400cba2b28SAlexander V. Chernikov uint32_t pipe; /* O_PIPE/O_QUEUE */ 20410cba2b28SAlexander V. Chernikov uint16_t divert; /* O_DIVERT/O_TEE */ 20420cba2b28SAlexander V. Chernikov uint16_t skipto; /* skipto, CALLRET */ 20430cba2b28SAlexander V. Chernikov uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ 20440cba2b28SAlexander V. Chernikov uint32_t fib; /* O_SETFIB */ 20450cba2b28SAlexander V. Chernikov uint32_t nat; /* O_NAT */ 20460cba2b28SAlexander V. Chernikov uint32_t nh4; 20470cba2b28SAlexander V. Chernikov uint8_t dscp; 20482530ed9eSAndrey V. Elsukov uint8_t spare0; 20492530ed9eSAndrey V. Elsukov uint16_t spare1; 20500cba2b28SAlexander V. Chernikov /* -- 32 bytes -- */ 20510cba2b28SAlexander V. Chernikov struct in6_addr nh6; 20520cba2b28SAlexander V. Chernikov uint32_t limit; /* O_LIMIT */ 20532530ed9eSAndrey V. Elsukov uint32_t zoneid; 20540cba2b28SAlexander V. Chernikov uint64_t refcnt; /* Number of references */ 20550cba2b28SAlexander V. Chernikov }; 20560cba2b28SAlexander V. Chernikov 205756707beeSMark Johnston static int 20580cba2b28SAlexander V. Chernikov compare_values(const void *_a, const void *_b) 20590cba2b28SAlexander V. Chernikov { 206056707beeSMark Johnston const struct _table_value *a, *b; 20610cba2b28SAlexander V. Chernikov 206256707beeSMark Johnston a = (const struct _table_value *)_a; 206356707beeSMark Johnston b = (const struct _table_value *)_b; 20640cba2b28SAlexander V. Chernikov 20650cba2b28SAlexander V. Chernikov if (a->spare1 < b->spare1) 20660cba2b28SAlexander V. Chernikov return (-1); 20670cba2b28SAlexander V. Chernikov else if (a->spare1 > b->spare1) 20680cba2b28SAlexander V. Chernikov return (1); 20690cba2b28SAlexander V. Chernikov 20700cba2b28SAlexander V. Chernikov return (0); 20710cba2b28SAlexander V. Chernikov } 20720cba2b28SAlexander V. Chernikov 20730cba2b28SAlexander V. Chernikov void 207456707beeSMark Johnston ipfw_list_values(int ac __unused, char *av[] __unused) 20750cba2b28SAlexander V. Chernikov { 207656707beeSMark Johnston char buf[128]; 20770cba2b28SAlexander V. Chernikov ipfw_obj_lheader *olh; 20780cba2b28SAlexander V. Chernikov struct _table_value *v; 207956707beeSMark Johnston uint32_t i, vmask; 208056707beeSMark Johnston int error; 20810cba2b28SAlexander V. Chernikov 20820cba2b28SAlexander V. Chernikov error = table_do_get_vlist(&olh); 20830cba2b28SAlexander V. Chernikov if (error != 0) 20840cba2b28SAlexander V. Chernikov err(EX_OSERR, "Unable to request value list"); 20850cba2b28SAlexander V. Chernikov 20860cba2b28SAlexander V. Chernikov vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ 20870cba2b28SAlexander V. Chernikov 20880cba2b28SAlexander V. Chernikov table_print_valheader(buf, sizeof(buf), vmask); 20890cba2b28SAlexander V. Chernikov printf("HEADER: %s\n", buf); 20900cba2b28SAlexander V. Chernikov v = (struct _table_value *)(olh + 1); 20910cba2b28SAlexander V. Chernikov qsort(v, olh->count, olh->objsize, compare_values); 20920cba2b28SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 20930cba2b28SAlexander V. Chernikov table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, 20940cba2b28SAlexander V. Chernikov vmask, 0); 2095d3de6c1dSAlexander V. Chernikov printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf); 20960cba2b28SAlexander V. Chernikov v = (struct _table_value *)((caddr_t)v + olh->objsize); 20970cba2b28SAlexander V. Chernikov } 20980cba2b28SAlexander V. Chernikov 20990cba2b28SAlexander V. Chernikov free(olh); 21000cba2b28SAlexander V. Chernikov } 21010cba2b28SAlexander V. Chernikov 21026c2997ffSAlexander V. Chernikov int 21032acdf79fSAndrey V. Elsukov table_check_name(const char *tablename) 21046c2997ffSAlexander V. Chernikov { 21056c2997ffSAlexander V. Chernikov 21062acdf79fSAndrey V. Elsukov if (ipfw_check_object_name(tablename) != 0) 21076c2997ffSAlexander V. Chernikov return (EINVAL); 2108ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 2109ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 2110ac35ff17SAlexander V. Chernikov return (EINVAL); 21116c2997ffSAlexander V. Chernikov return (0); 21126c2997ffSAlexander V. Chernikov } 21136c2997ffSAlexander V. Chernikov 2114