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 34f1220db8SAlexander V. Chernikov #include <net/if.h> 35f1220db8SAlexander V. Chernikov #include <netinet/in.h> 36f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h> 37f1220db8SAlexander V. Chernikov #include <arpa/inet.h> 382530ed9eSAndrey V. Elsukov #include <netdb.h> 39f1220db8SAlexander V. Chernikov 40f1220db8SAlexander V. Chernikov #include "ipfw2.h" 41f1220db8SAlexander V. Chernikov 42ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 433a845e10SAlexander V. Chernikov int add, int quiet, int update, int atomic); 44ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh); 45ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh); 46ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 47adf3b2b9SAlexander V. Chernikov static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i); 4846d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second); 49adf3b2b9SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 50adf3b2b9SAlexander V. Chernikov static void table_modify(ipfw_obj_header *oh, int ac, char *av[]); 51adf3b2b9SAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 524f43138aSAlexander V. Chernikov static void table_lock(ipfw_obj_header *oh, int lock); 5346d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second); 54ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 55f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 56f1220db8SAlexander V. Chernikov 57421c5838SAndrey V. Elsukov static int table_destroy_one(ipfw_xtable_info *i, void *arg); 58f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 59f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 60720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); 61f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 6281d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 63f1220db8SAlexander V. Chernikov 64ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 650cba2b28SAlexander V. Chernikov char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi); 66ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 670cba2b28SAlexander V. Chernikov char *arg, uint8_t type, uint32_t vmask); 680cba2b28SAlexander V. Chernikov static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 690cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip); 70ac35ff17SAlexander V. Chernikov 71f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 72f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 73f1220db8SAlexander V. Chernikov 74f1220db8SAlexander V. Chernikov #ifndef s6_addr32 75f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 76f1220db8SAlexander V. Chernikov #endif 77f1220db8SAlexander V. Chernikov 78ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 79c21034b7SAlexander V. Chernikov { "addr", IPFW_TABLE_ADDR }, 80ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 81b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 82914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 83ac35ff17SAlexander V. Chernikov { NULL, 0 } 84ac35ff17SAlexander V. Chernikov }; 85ac35ff17SAlexander V. Chernikov 86ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 870cba2b28SAlexander V. Chernikov { "skipto", IPFW_VTYPE_SKIPTO }, 880cba2b28SAlexander V. Chernikov { "pipe", IPFW_VTYPE_PIPE }, 890cba2b28SAlexander V. Chernikov { "fib", IPFW_VTYPE_FIB }, 900cba2b28SAlexander V. Chernikov { "nat", IPFW_VTYPE_NAT }, 910cba2b28SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 920cba2b28SAlexander V. Chernikov { "tag", IPFW_VTYPE_TAG }, 930cba2b28SAlexander V. Chernikov { "divert", IPFW_VTYPE_DIVERT }, 940cba2b28SAlexander V. Chernikov { "netgraph", IPFW_VTYPE_NETGRAPH }, 950cba2b28SAlexander V. Chernikov { "limit", IPFW_VTYPE_LIMIT }, 960cba2b28SAlexander V. Chernikov { "ipv4", IPFW_VTYPE_NH4 }, 970cba2b28SAlexander V. Chernikov { "ipv6", IPFW_VTYPE_NH6 }, 98adf3b2b9SAlexander V. Chernikov { NULL, 0 } 99adf3b2b9SAlexander V. Chernikov }; 100adf3b2b9SAlexander V. Chernikov 101ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 102ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 103ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 10446d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 105ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 106ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 107adf3b2b9SAlexander V. Chernikov { "modify", TOK_MODIFY }, 10846d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 109ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 110358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 111ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 11281d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 1133a845e10SAlexander V. Chernikov { "atomic", TOK_ATOMIC }, 1144f43138aSAlexander V. Chernikov { "lock", TOK_LOCK }, 1154f43138aSAlexander V. Chernikov { "unlock", TOK_UNLOCK }, 116ac35ff17SAlexander V. Chernikov { NULL, 0 } 117ac35ff17SAlexander V. Chernikov }; 118ac35ff17SAlexander V. Chernikov 119f1220db8SAlexander V. Chernikov static int 120f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 121f1220db8SAlexander V. Chernikov { 122f1220db8SAlexander V. Chernikov struct hostent *he; 123f1220db8SAlexander V. Chernikov 124f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 125f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 126f1220db8SAlexander V. Chernikov return(-1); 127f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 128f1220db8SAlexander V. Chernikov } 129f1220db8SAlexander V. Chernikov return(0); 130f1220db8SAlexander V. Chernikov } 131f1220db8SAlexander V. Chernikov 132f1220db8SAlexander V. Chernikov /* 133f1220db8SAlexander V. Chernikov * This one handles all table-related commands 134ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 135be695df9SAlexander V. Chernikov * ipfw table NAME modify ... 136421c5838SAndrey V. Elsukov * ipfw table {NAME | all} destroy 137be695df9SAlexander V. Chernikov * ipfw table NAME swap NAME 138be695df9SAlexander V. Chernikov * ipfw table NAME lock 139be695df9SAlexander V. Chernikov * ipfw table NAME unlock 140ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 141be695df9SAlexander V. Chernikov * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] .. 142be695df9SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] [addr[/masklen]] .. 143be695df9SAlexander V. Chernikov * ipfw table NAME lookup addr 144ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 145ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 146ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 147be695df9SAlexander V. Chernikov * ipfw table {NAME | all} detail 148f1220db8SAlexander V. Chernikov */ 149f1220db8SAlexander V. Chernikov void 150f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 151f1220db8SAlexander V. Chernikov { 152ac35ff17SAlexander V. Chernikov int do_add, is_all; 1533a845e10SAlexander V. Chernikov int atomic, error, tcmd; 154ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 155ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 156f1220db8SAlexander V. Chernikov char *tablename; 157d8caf56eSAndrey V. Elsukov uint8_t set; 158358b9d09SAlexander V. Chernikov void *arg; 159f1220db8SAlexander V. Chernikov 160ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 161ac35ff17SAlexander V. Chernikov is_all = 0; 162ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 163ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 164ac35ff17SAlexander V. Chernikov else 165ac35ff17SAlexander V. Chernikov set = 0; 166f1220db8SAlexander V. Chernikov 167f1220db8SAlexander V. Chernikov ac--; av++; 1689d099b4fSAlexander V. Chernikov NEED1("table needs name"); 169f1220db8SAlexander V. Chernikov tablename = *av; 170f1220db8SAlexander V. Chernikov 171ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 172ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 173ac35ff17SAlexander V. Chernikov oh.idx = 1; 174ac35ff17SAlexander V. Chernikov } else { 175ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 176ac35ff17SAlexander V. Chernikov is_all = 1; 177ac35ff17SAlexander V. Chernikov else 178ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 179ac35ff17SAlexander V. Chernikov } 180ac35ff17SAlexander V. Chernikov ac--; av++; 1819d099b4fSAlexander V. Chernikov NEED1("table needs command"); 182ac35ff17SAlexander V. Chernikov 183be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 1843a845e10SAlexander V. Chernikov /* Check if atomic operation was requested */ 1853a845e10SAlexander V. Chernikov atomic = 0; 1863a845e10SAlexander V. Chernikov if (tcmd == TOK_ATOMIC) { 1873a845e10SAlexander V. Chernikov ac--; av++; 1883a845e10SAlexander V. Chernikov NEED1("atomic needs command"); 189be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 1903a845e10SAlexander V. Chernikov switch (tcmd) { 1913a845e10SAlexander V. Chernikov case TOK_ADD: 1923a845e10SAlexander V. Chernikov break; 1933a845e10SAlexander V. Chernikov default: 1943a845e10SAlexander V. Chernikov errx(EX_USAGE, "atomic is not compatible with %s", *av); 1953a845e10SAlexander V. Chernikov } 1963a845e10SAlexander V. Chernikov atomic = 1; 1973a845e10SAlexander V. Chernikov } 198ac35ff17SAlexander V. Chernikov 199ac35ff17SAlexander V. Chernikov switch (tcmd) { 200ac35ff17SAlexander V. Chernikov case TOK_LIST: 201ac35ff17SAlexander V. Chernikov case TOK_INFO: 202358b9d09SAlexander V. Chernikov case TOK_DETAIL: 203ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 204421c5838SAndrey V. Elsukov case TOK_DESTROY: 205ac35ff17SAlexander V. Chernikov break; 206ac35ff17SAlexander V. Chernikov default: 207ac35ff17SAlexander V. Chernikov if (is_all != 0) 208ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 209ac35ff17SAlexander V. Chernikov } 210ac35ff17SAlexander V. Chernikov 211ac35ff17SAlexander V. Chernikov switch (tcmd) { 212ac35ff17SAlexander V. Chernikov case TOK_ADD: 213ac35ff17SAlexander V. Chernikov case TOK_DEL: 214f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 215f1220db8SAlexander V. Chernikov ac--; av++; 2163a845e10SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet, 2173a845e10SAlexander V. Chernikov co.do_quiet, atomic); 218ac35ff17SAlexander V. Chernikov break; 219ac35ff17SAlexander V. Chernikov case TOK_CREATE: 220f1220db8SAlexander V. Chernikov ac--; av++; 221ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 222ac35ff17SAlexander V. Chernikov break; 223adf3b2b9SAlexander V. Chernikov case TOK_MODIFY: 224adf3b2b9SAlexander V. Chernikov ac--; av++; 225adf3b2b9SAlexander V. Chernikov table_modify(&oh, ac, av); 226adf3b2b9SAlexander V. Chernikov break; 227ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 228421c5838SAndrey V. Elsukov if (is_all == 0) { 22976d03257SAndrey V. Elsukov if (table_destroy(&oh) == 0) 23076d03257SAndrey V. Elsukov break; 23176d03257SAndrey V. Elsukov if (errno != ESRCH) 232421c5838SAndrey V. Elsukov err(EX_OSERR, "failed to destroy table %s", 233421c5838SAndrey V. Elsukov tablename); 23476d03257SAndrey V. Elsukov /* ESRCH isn't fatal, warn if not quiet mode */ 23576d03257SAndrey V. Elsukov if (co.do_quiet == 0) 23676d03257SAndrey V. Elsukov warn("failed to destroy table %s", tablename); 237421c5838SAndrey V. Elsukov } else { 238421c5838SAndrey V. Elsukov error = tables_foreach(table_destroy_one, &oh, 1); 239421c5838SAndrey V. Elsukov if (error != 0) 240421c5838SAndrey V. Elsukov err(EX_OSERR, 241421c5838SAndrey V. Elsukov "failed to destroy tables list"); 242421c5838SAndrey V. Elsukov } 243ac35ff17SAlexander V. Chernikov break; 244ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 245f1220db8SAlexander V. Chernikov if (is_all == 0) { 24676d03257SAndrey V. Elsukov if ((error = table_flush(&oh)) == 0) 24776d03257SAndrey V. Elsukov break; 24876d03257SAndrey V. Elsukov if (errno != ESRCH) 249f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 250f1220db8SAlexander V. Chernikov tablename); 25176d03257SAndrey V. Elsukov /* ESRCH isn't fatal, warn if not quiet mode */ 25276d03257SAndrey V. Elsukov if (co.do_quiet == 0) 25376d03257SAndrey V. Elsukov warn("failed to flush table %s info", 25476d03257SAndrey V. Elsukov tablename); 255f1220db8SAlexander V. Chernikov } else { 256ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 257f1220db8SAlexander V. Chernikov if (error != 0) 258f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 25976d03257SAndrey V. Elsukov /* XXX: we ignore errors here */ 260f1220db8SAlexander V. Chernikov } 261ac35ff17SAlexander V. Chernikov break; 26246d52008SAlexander V. Chernikov case TOK_SWAP: 26346d52008SAlexander V. Chernikov ac--; av++; 26446d52008SAlexander V. Chernikov NEED1("second table name required"); 26546d52008SAlexander V. Chernikov table_swap(&oh, *av); 26646d52008SAlexander V. Chernikov break; 2674f43138aSAlexander V. Chernikov case TOK_LOCK: 2684f43138aSAlexander V. Chernikov case TOK_UNLOCK: 2694f43138aSAlexander V. Chernikov table_lock(&oh, (tcmd == TOK_LOCK)); 2704f43138aSAlexander V. Chernikov break; 271358b9d09SAlexander V. Chernikov case TOK_DETAIL: 272ac35ff17SAlexander V. Chernikov case TOK_INFO: 273358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 274f1220db8SAlexander V. Chernikov if (is_all == 0) { 275ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 276f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 277358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 278f1220db8SAlexander V. Chernikov } else { 279358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 280f1220db8SAlexander V. Chernikov if (error != 0) 281f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 282f1220db8SAlexander V. Chernikov } 283ac35ff17SAlexander V. Chernikov break; 284ac35ff17SAlexander V. Chernikov case TOK_LIST: 28510e3bebfSBryan Drewery arg = is_all ? (void*)1 : NULL; 286ac35ff17SAlexander V. Chernikov if (is_all == 0) { 287ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 288ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 289ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 2902b3d6647SBryan Drewery table_show_one(&i, arg); 291f1220db8SAlexander V. Chernikov } else { 2922b3d6647SBryan Drewery error = tables_foreach(table_show_one, arg, 1); 293ac35ff17SAlexander V. Chernikov if (error != 0) 294ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 295f1220db8SAlexander V. Chernikov } 296ac35ff17SAlexander V. Chernikov break; 29781d3153dSAlexander V. Chernikov case TOK_LOOKUP: 29881d3153dSAlexander V. Chernikov ac--; av++; 29981d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 30081d3153dSAlexander V. Chernikov break; 301f1220db8SAlexander V. Chernikov } 302f1220db8SAlexander V. Chernikov } 303f1220db8SAlexander V. Chernikov 304d8caf56eSAndrey V. Elsukov void 305d8caf56eSAndrey V. Elsukov table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set, 3062acdf79fSAndrey V. Elsukov uint16_t uidx) 307f1220db8SAlexander V. Chernikov { 308f1220db8SAlexander V. Chernikov 309563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 310f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 311f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 312ac35ff17SAlexander V. Chernikov ntlv->set = set; 313f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 314f1220db8SAlexander V. Chernikov } 315f1220db8SAlexander V. Chernikov 316f1220db8SAlexander V. Chernikov static void 317f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 318f1220db8SAlexander V. Chernikov { 319f1220db8SAlexander V. Chernikov 320f1220db8SAlexander V. Chernikov oh->idx = 1; 32181d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 322ac35ff17SAlexander V. Chernikov } 323ac35ff17SAlexander V. Chernikov 324ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 325ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 326ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 327ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 3284c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 3294f43138aSAlexander V. Chernikov { "locked", TOK_LOCK }, 330*05ab1ef6SAndrey V. Elsukov { "missing", TOK_MISSING }, 331*05ab1ef6SAndrey V. Elsukov { "or-flush", TOK_ORFLUSH }, 332ac35ff17SAlexander V. Chernikov { NULL, 0 } 333ac35ff17SAlexander V. Chernikov }; 334ac35ff17SAlexander V. Chernikov 335914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 336914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 337914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 338914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 339914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 340914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 341914bffb6SAlexander V. Chernikov { NULL, 0 } 342914bffb6SAlexander V. Chernikov }; 343914bffb6SAlexander V. Chernikov 344914bffb6SAlexander V. Chernikov int 345914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 346914bffb6SAlexander V. Chernikov { 3470cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 3480cba2b28SAlexander V. Chernikov char *e; 349914bffb6SAlexander V. Chernikov 350914bffb6SAlexander V. Chernikov /* Parse type options */ 351914bffb6SAlexander V. Chernikov switch(ttype) { 352914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 353914bffb6SAlexander V. Chernikov fset = fclear = 0; 3540cba2b28SAlexander V. Chernikov if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0) 3550cba2b28SAlexander V. Chernikov errx(EX_USAGE, 3560cba2b28SAlexander V. Chernikov "unable to parse flow option %s", e); 357914bffb6SAlexander V. Chernikov *tflags = fset; 358914bffb6SAlexander V. Chernikov break; 359914bffb6SAlexander V. Chernikov default: 360914bffb6SAlexander V. Chernikov return (EX_USAGE); 361914bffb6SAlexander V. Chernikov } 362914bffb6SAlexander V. Chernikov 363914bffb6SAlexander V. Chernikov return (0); 364914bffb6SAlexander V. Chernikov } 365914bffb6SAlexander V. Chernikov 366914bffb6SAlexander V. Chernikov void 367914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 368914bffb6SAlexander V. Chernikov { 369914bffb6SAlexander V. Chernikov const char *tname; 370914bffb6SAlexander V. Chernikov int l; 371914bffb6SAlexander V. Chernikov 372914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 373914bffb6SAlexander V. Chernikov tname = "unknown"; 374914bffb6SAlexander V. Chernikov 375914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 376914bffb6SAlexander V. Chernikov tbuf += l; 377914bffb6SAlexander V. Chernikov size -= l; 378914bffb6SAlexander V. Chernikov 379914bffb6SAlexander V. Chernikov switch(type) { 380914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 381914bffb6SAlexander V. Chernikov if (tflags != 0) { 382914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 383914bffb6SAlexander V. Chernikov l--; 384914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 385914bffb6SAlexander V. Chernikov } 386914bffb6SAlexander V. Chernikov break; 387914bffb6SAlexander V. Chernikov } 388914bffb6SAlexander V. Chernikov } 389914bffb6SAlexander V. Chernikov 390ac35ff17SAlexander V. Chernikov /* 391ac35ff17SAlexander V. Chernikov * Creates new table 392ac35ff17SAlexander V. Chernikov * 393c21034b7SAlexander V. Chernikov * ipfw table NAME create [ type { addr | iface | number | flow } ] 394*05ab1ef6SAndrey V. Elsukov * [ algo algoname ] [missing] [or-flush] 395ac35ff17SAlexander V. Chernikov */ 396ac35ff17SAlexander V. Chernikov static void 397ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 398ac35ff17SAlexander V. Chernikov { 399*05ab1ef6SAndrey V. Elsukov ipfw_xtable_info xi, xie; 400*05ab1ef6SAndrey V. Elsukov int error, missing, orflush, tcmd, val; 4010cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 4020cba2b28SAlexander V. Chernikov char *e, *p; 403ac35ff17SAlexander V. Chernikov char tbuf[128]; 404ac35ff17SAlexander V. Chernikov 405*05ab1ef6SAndrey V. Elsukov missing = orflush = 0; 406ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 407ac35ff17SAlexander V. Chernikov while (ac > 0) { 408be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 409ac35ff17SAlexander V. Chernikov ac--; av++; 410ac35ff17SAlexander V. Chernikov 411ac35ff17SAlexander V. Chernikov switch (tcmd) { 4124c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 4134c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 4144c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 4154c0c07a5SAlexander V. Chernikov ac--; av++; 4164c0c07a5SAlexander V. Chernikov break; 417ac35ff17SAlexander V. Chernikov case TOK_TYPE: 418ac35ff17SAlexander V. Chernikov NEED1("table type required"); 419914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 420914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 421914bffb6SAlexander V. Chernikov *p++ = '\0'; 422ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 423914bffb6SAlexander V. Chernikov if (val == -1) { 424914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 425914bffb6SAlexander V. Chernikov ", "); 426914bffb6SAlexander V. Chernikov errx(EX_USAGE, 427914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 428ac35ff17SAlexander V. Chernikov *av, tbuf); 429914bffb6SAlexander V. Chernikov } 430914bffb6SAlexander V. Chernikov xi.type = val; 431914bffb6SAlexander V. Chernikov if (p != NULL) { 432914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 433914bffb6SAlexander V. Chernikov if (error != 0) 434914bffb6SAlexander V. Chernikov errx(EX_USAGE, 435914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 436914bffb6SAlexander V. Chernikov } 437914bffb6SAlexander V. Chernikov ac--; av++; 438ac35ff17SAlexander V. Chernikov break; 439ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 440ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 4410cba2b28SAlexander V. Chernikov fset = fclear = 0; 4420cba2b28SAlexander V. Chernikov val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear); 443ac35ff17SAlexander V. Chernikov if (val != -1) { 4440cba2b28SAlexander V. Chernikov xi.vmask = fset; 445ac35ff17SAlexander V. Chernikov ac--; av++; 446ac35ff17SAlexander V. Chernikov break; 447ac35ff17SAlexander V. Chernikov } 448ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 449ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 4500cba2b28SAlexander V. Chernikov e, tbuf); 451adf3b2b9SAlexander V. Chernikov break; 452ac35ff17SAlexander V. Chernikov case TOK_ALGO: 453ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 454ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 455ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 456ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 457ac35ff17SAlexander V. Chernikov ac--; av++; 458ac35ff17SAlexander V. Chernikov break; 4594f43138aSAlexander V. Chernikov case TOK_LOCK: 4604f43138aSAlexander V. Chernikov xi.flags |= IPFW_TGFLAGS_LOCKED; 4614f43138aSAlexander V. Chernikov break; 462*05ab1ef6SAndrey V. Elsukov case TOK_ORFLUSH: 463*05ab1ef6SAndrey V. Elsukov orflush = 1; 464*05ab1ef6SAndrey V. Elsukov /* FALLTHROUGH */ 465*05ab1ef6SAndrey V. Elsukov case TOK_MISSING: 466*05ab1ef6SAndrey V. Elsukov missing = 1; 467*05ab1ef6SAndrey V. Elsukov break; 468ac35ff17SAlexander V. Chernikov } 469ac35ff17SAlexander V. Chernikov } 470ac35ff17SAlexander V. Chernikov 471463a577bSEitan Adler /* Set some defaults to preserve compatibility. */ 472fd0869d5SAlexander V. Chernikov if (xi.algoname[0] == '\0' && xi.type == 0) 473c21034b7SAlexander V. Chernikov xi.type = IPFW_TABLE_ADDR; 4740cba2b28SAlexander V. Chernikov if (xi.vmask == 0) 4750cba2b28SAlexander V. Chernikov xi.vmask = IPFW_VTYPE_LEGACY; 476fd0869d5SAlexander V. Chernikov 477*05ab1ef6SAndrey V. Elsukov error = table_do_create(oh, &xi); 478*05ab1ef6SAndrey V. Elsukov 479*05ab1ef6SAndrey V. Elsukov if (error == 0) 480*05ab1ef6SAndrey V. Elsukov return; 481*05ab1ef6SAndrey V. Elsukov 482*05ab1ef6SAndrey V. Elsukov if (errno != EEXIST || missing == 0) 483ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 484*05ab1ef6SAndrey V. Elsukov 485*05ab1ef6SAndrey V. Elsukov /* Check that existing table is the same we are trying to create */ 486*05ab1ef6SAndrey V. Elsukov if (table_get_info(oh, &xie) != 0) 487*05ab1ef6SAndrey V. Elsukov err(EX_OSERR, "Existing table check failed"); 488*05ab1ef6SAndrey V. Elsukov 489*05ab1ef6SAndrey V. Elsukov if (xi.limit != xie.limit || xi.type != xie.type || 490*05ab1ef6SAndrey V. Elsukov xi.tflags != xie.tflags || xi.vmask != xie.vmask || ( 491*05ab1ef6SAndrey V. Elsukov xi.algoname[0] != '\0' && strcmp(xi.algoname, 492*05ab1ef6SAndrey V. Elsukov xie.algoname) != 0) || xi.flags != xie.flags) 493*05ab1ef6SAndrey V. Elsukov errx(EX_DATAERR, "The existing table is not compatible " 494*05ab1ef6SAndrey V. Elsukov "with one you are creating."); 495*05ab1ef6SAndrey V. Elsukov 496*05ab1ef6SAndrey V. Elsukov /* Flush existing table if instructed to do so */ 497*05ab1ef6SAndrey V. Elsukov if (orflush != 0 && table_flush(oh) != 0) 498*05ab1ef6SAndrey V. Elsukov err(EX_OSERR, "Table flush on creation failed"); 499f1220db8SAlexander V. Chernikov } 500f1220db8SAlexander V. Chernikov 501f1220db8SAlexander V. Chernikov /* 502ac35ff17SAlexander V. Chernikov * Creates new table 503ac35ff17SAlexander V. Chernikov * 504ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 505ac35ff17SAlexander V. Chernikov * 506f1220db8SAlexander V. Chernikov * Returns 0 on success. 507f1220db8SAlexander V. Chernikov */ 508f1220db8SAlexander V. Chernikov static int 509ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 510f1220db8SAlexander V. Chernikov { 511ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 512ac35ff17SAlexander V. Chernikov int error; 513f1220db8SAlexander V. Chernikov 514ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 515ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 516ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 517ac35ff17SAlexander V. Chernikov 518ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 519ac35ff17SAlexander V. Chernikov 520ac35ff17SAlexander V. Chernikov return (error); 521ac35ff17SAlexander V. Chernikov } 522ac35ff17SAlexander V. Chernikov 523ac35ff17SAlexander V. Chernikov /* 524adf3b2b9SAlexander V. Chernikov * Modifies existing table 525adf3b2b9SAlexander V. Chernikov * 5260cba2b28SAlexander V. Chernikov * ipfw table NAME modify [ limit number ] 527adf3b2b9SAlexander V. Chernikov */ 528adf3b2b9SAlexander V. Chernikov static void 529adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[]) 530adf3b2b9SAlexander V. Chernikov { 531adf3b2b9SAlexander V. Chernikov ipfw_xtable_info xi; 532b6462881SAlexander V. Chernikov int tcmd; 533adf3b2b9SAlexander V. Chernikov 534adf3b2b9SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 535adf3b2b9SAlexander V. Chernikov 536adf3b2b9SAlexander V. Chernikov while (ac > 0) { 537be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 538adf3b2b9SAlexander V. Chernikov ac--; av++; 539adf3b2b9SAlexander V. Chernikov 540adf3b2b9SAlexander V. Chernikov switch (tcmd) { 541adf3b2b9SAlexander V. Chernikov case TOK_LIMIT: 542adf3b2b9SAlexander V. Chernikov NEED1("limit value required"); 543adf3b2b9SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 544adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LIMIT; 545adf3b2b9SAlexander V. Chernikov ac--; av++; 546adf3b2b9SAlexander V. Chernikov break; 5470cba2b28SAlexander V. Chernikov default: 5486ef82c0aSAlan Somers errx(EX_USAGE, "cmd is not supported for modification"); 549adf3b2b9SAlexander V. Chernikov } 550adf3b2b9SAlexander V. Chernikov } 551adf3b2b9SAlexander V. Chernikov 552b6462881SAlexander V. Chernikov if (table_do_modify(oh, &xi) != 0) 553adf3b2b9SAlexander V. Chernikov err(EX_OSERR, "Table modification failed"); 554adf3b2b9SAlexander V. Chernikov } 555adf3b2b9SAlexander V. Chernikov 556adf3b2b9SAlexander V. Chernikov /* 557adf3b2b9SAlexander V. Chernikov * Modifies existing table. 558adf3b2b9SAlexander V. Chernikov * 559adf3b2b9SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 560adf3b2b9SAlexander V. Chernikov * 561adf3b2b9SAlexander V. Chernikov * Returns 0 on success. 562adf3b2b9SAlexander V. Chernikov */ 563adf3b2b9SAlexander V. Chernikov static int 564adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 565adf3b2b9SAlexander V. Chernikov { 566adf3b2b9SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 567adf3b2b9SAlexander V. Chernikov int error; 568adf3b2b9SAlexander V. Chernikov 569adf3b2b9SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 570adf3b2b9SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 571adf3b2b9SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 572adf3b2b9SAlexander V. Chernikov 573adf3b2b9SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 574adf3b2b9SAlexander V. Chernikov 575adf3b2b9SAlexander V. Chernikov return (error); 576adf3b2b9SAlexander V. Chernikov } 5774f43138aSAlexander V. Chernikov 5784f43138aSAlexander V. Chernikov /* 5794f43138aSAlexander V. Chernikov * Locks or unlocks given table 5804f43138aSAlexander V. Chernikov */ 5814f43138aSAlexander V. Chernikov static void 5824f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock) 5834f43138aSAlexander V. Chernikov { 5844f43138aSAlexander V. Chernikov ipfw_xtable_info xi; 5854f43138aSAlexander V. Chernikov 5864f43138aSAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 5874f43138aSAlexander V. Chernikov 5884f43138aSAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LOCK; 5894f43138aSAlexander V. Chernikov xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; 5904f43138aSAlexander V. Chernikov 591b6462881SAlexander V. Chernikov if (table_do_modify(oh, &xi) != 0) 5924f43138aSAlexander V. Chernikov err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); 5934f43138aSAlexander V. Chernikov } 5944f43138aSAlexander V. Chernikov 595adf3b2b9SAlexander V. Chernikov /* 596ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 597ac35ff17SAlexander V. Chernikov * Returns 0 on success. 598ac35ff17SAlexander V. Chernikov */ 599ac35ff17SAlexander V. Chernikov static int 600ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 601ac35ff17SAlexander V. Chernikov { 602ac35ff17SAlexander V. Chernikov 603ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 604f1220db8SAlexander V. Chernikov return (-1); 605f1220db8SAlexander V. Chernikov 606f1220db8SAlexander V. Chernikov return (0); 607f1220db8SAlexander V. Chernikov } 608f1220db8SAlexander V. Chernikov 609421c5838SAndrey V. Elsukov static int 610421c5838SAndrey V. Elsukov table_destroy_one(ipfw_xtable_info *i, void *arg) 611421c5838SAndrey V. Elsukov { 612421c5838SAndrey V. Elsukov ipfw_obj_header *oh; 613421c5838SAndrey V. Elsukov 614421c5838SAndrey V. Elsukov oh = (ipfw_obj_header *)arg; 615421c5838SAndrey V. Elsukov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 616421c5838SAndrey V. Elsukov if (table_destroy(oh) != 0) { 617421c5838SAndrey V. Elsukov if (co.do_quiet == 0) 618421c5838SAndrey V. Elsukov warn("failed to destroy table(%s) in set %u", 619421c5838SAndrey V. Elsukov i->tablename, i->set); 620421c5838SAndrey V. Elsukov return (-1); 621421c5838SAndrey V. Elsukov } 622421c5838SAndrey V. Elsukov return (0); 623421c5838SAndrey V. Elsukov } 624421c5838SAndrey V. Elsukov 625f1220db8SAlexander V. Chernikov /* 626ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 627f1220db8SAlexander V. Chernikov * Returns 0 on success. 628f1220db8SAlexander V. Chernikov */ 629f1220db8SAlexander V. Chernikov static int 630ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 631f1220db8SAlexander V. Chernikov { 632f1220db8SAlexander V. Chernikov 633ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 634f1220db8SAlexander V. Chernikov return (-1); 635f1220db8SAlexander V. Chernikov 636f1220db8SAlexander V. Chernikov return (0); 637f1220db8SAlexander V. Chernikov } 638f1220db8SAlexander V. Chernikov 63946d52008SAlexander V. Chernikov static int 64046d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 64146d52008SAlexander V. Chernikov { 64246d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 64346d52008SAlexander V. Chernikov int error; 64446d52008SAlexander V. Chernikov 64546d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 64646d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 64746d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 64846d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 64946d52008SAlexander V. Chernikov 65046d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 65146d52008SAlexander V. Chernikov 65246d52008SAlexander V. Chernikov return (error); 65346d52008SAlexander V. Chernikov } 65446d52008SAlexander V. Chernikov 65546d52008SAlexander V. Chernikov /* 65646d52008SAlexander V. Chernikov * Swaps given table with @second one. 65746d52008SAlexander V. Chernikov */ 65846d52008SAlexander V. Chernikov static int 65946d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 66046d52008SAlexander V. Chernikov { 66146d52008SAlexander V. Chernikov 66246d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 66346d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 66446d52008SAlexander V. Chernikov 66576d03257SAndrey V. Elsukov if (table_do_swap(oh, second) == 0) 66676d03257SAndrey V. Elsukov return (0); 66746d52008SAlexander V. Chernikov 66876d03257SAndrey V. Elsukov switch (errno) { 66946d52008SAlexander V. Chernikov case EINVAL: 67046d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 67146d52008SAlexander V. Chernikov case EFBIG: 67246d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 67346d52008SAlexander V. Chernikov } 67446d52008SAlexander V. Chernikov 67546d52008SAlexander V. Chernikov return (0); 67646d52008SAlexander V. Chernikov } 67746d52008SAlexander V. Chernikov 67846d52008SAlexander V. Chernikov 679f1220db8SAlexander V. Chernikov /* 680ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 681f1220db8SAlexander V. Chernikov * it inside @i. 682f1220db8SAlexander V. Chernikov * Returns 0 on success. 683f1220db8SAlexander V. Chernikov */ 684f1220db8SAlexander V. Chernikov static int 685ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 686f1220db8SAlexander V. Chernikov { 687f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 688f1220db8SAlexander V. Chernikov size_t sz; 689f1220db8SAlexander V. Chernikov 690f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 691f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 692ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 693f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 694f1220db8SAlexander V. Chernikov 695b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0) 696b6462881SAlexander V. Chernikov return (errno); 697f1220db8SAlexander V. Chernikov 698f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 699ac35ff17SAlexander V. Chernikov return (EINVAL); 700f1220db8SAlexander V. Chernikov 701f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 702f1220db8SAlexander V. Chernikov 703f1220db8SAlexander V. Chernikov return (0); 704f1220db8SAlexander V. Chernikov } 705f1220db8SAlexander V. Chernikov 7065f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 7075f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 7085f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 7095f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 7105f379342SAlexander V. Chernikov { NULL, 0 } 7115f379342SAlexander V. Chernikov }; 7125f379342SAlexander V. Chernikov 7135f379342SAlexander V. Chernikov struct ta_cldata { 7145f379342SAlexander V. Chernikov uint8_t taclass; 7155f379342SAlexander V. Chernikov uint8_t spare4; 7165f379342SAlexander V. Chernikov uint16_t itemsize; 7175f379342SAlexander V. Chernikov uint16_t itemsize6; 7185f379342SAlexander V. Chernikov uint32_t size; 7195f379342SAlexander V. Chernikov uint32_t count; 7205f379342SAlexander V. Chernikov }; 7215f379342SAlexander V. Chernikov 7225f379342SAlexander V. Chernikov /* 7235f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 7245f379342SAlexander V. Chernikov */ 7255f379342SAlexander V. Chernikov static void 7265f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 7275f379342SAlexander V. Chernikov const char *af, const char *taclass) 7285f379342SAlexander V. Chernikov { 7295f379342SAlexander V. Chernikov 7305f379342SAlexander V. Chernikov switch (d->taclass) { 7315f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 7325f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 7335f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7345f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7355f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 7365f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 7375f379342SAlexander V. Chernikov else 7385f379342SAlexander V. Chernikov printf(" size: %u items: %u " 7395f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7405f379342SAlexander V. Chernikov d->size, d->count, 7415f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 7425f379342SAlexander V. Chernikov break; 7435f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 7445f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7455f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7465f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 7475f379342SAlexander V. Chernikov d->count, d->itemsize); 7485f379342SAlexander V. Chernikov else 7495f379342SAlexander V. Chernikov printf(" items: %u " 7505f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7515f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 7525f379342SAlexander V. Chernikov break; 7535f379342SAlexander V. Chernikov default: 7545f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 7555f379342SAlexander V. Chernikov } 7565f379342SAlexander V. Chernikov } 7575f379342SAlexander V. Chernikov 7580cba2b28SAlexander V. Chernikov static void 7590cba2b28SAlexander V. Chernikov table_print_valheader(char *buf, size_t bufsize, uint32_t vmask) 7600cba2b28SAlexander V. Chernikov { 7610cba2b28SAlexander V. Chernikov 7620cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 7630cba2b28SAlexander V. Chernikov snprintf(buf, bufsize, "legacy"); 7640cba2b28SAlexander V. Chernikov return; 7650cba2b28SAlexander V. Chernikov } 7660cba2b28SAlexander V. Chernikov 7678a6dbb64SAlexander V. Chernikov memset(buf, 0, bufsize); 7680cba2b28SAlexander V. Chernikov print_flags_buffer(buf, bufsize, tablevaltypes, vmask); 7690cba2b28SAlexander V. Chernikov } 7700cba2b28SAlexander V. Chernikov 771f1220db8SAlexander V. Chernikov /* 772f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 773f1220db8SAlexander V. Chernikov */ 774f1220db8SAlexander V. Chernikov static int 775f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 776f1220db8SAlexander V. Chernikov { 7770cba2b28SAlexander V. Chernikov const char *vtype; 7785f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 7795f379342SAlexander V. Chernikov int afdata, afitem; 7805f379342SAlexander V. Chernikov struct ta_cldata d; 781adf3b2b9SAlexander V. Chernikov char ttype[64], tvtype[64]; 782f1220db8SAlexander V. Chernikov 783914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 7840cba2b28SAlexander V. Chernikov table_print_valheader(tvtype, sizeof(tvtype), i->vmask); 785ac35ff17SAlexander V. Chernikov 786914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 7874f43138aSAlexander V. Chernikov if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) 7884f43138aSAlexander V. Chernikov printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); 7894f43138aSAlexander V. Chernikov else 790914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 7910cba2b28SAlexander V. Chernikov printf(" references: %u, valtype: %s\n", i->refcnt, tvtype); 7929d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 793f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 7944c0c07a5SAlexander V. Chernikov if (i->limit > 0) 7954c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 796f1220db8SAlexander V. Chernikov 797358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 798358b9d09SAlexander V. Chernikov if (arg == NULL) 799358b9d09SAlexander V. Chernikov return (0); 800358b9d09SAlexander V. Chernikov 8015f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 8025f379342SAlexander V. Chernikov return (0); 8035f379342SAlexander V. Chernikov tainfo = &i->ta_info; 8045f379342SAlexander V. Chernikov 8055f379342SAlexander V. Chernikov afdata = 0; 8065f379342SAlexander V. Chernikov afitem = 0; 8075f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 8085f379342SAlexander V. Chernikov afdata = 1; 8095f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 8105f379342SAlexander V. Chernikov afitem = 1; 8115f379342SAlexander V. Chernikov 8125f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 8135f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 8145f379342SAlexander V. Chernikov d.size = tainfo->size4; 8155f379342SAlexander V. Chernikov d.count = tainfo->count4; 8165f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 8175f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 8185f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 8195f379342SAlexander V. Chernikov else 8205f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 8215f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 8225f379342SAlexander V. Chernikov vtype = "unknown"; 8235f379342SAlexander V. Chernikov 8245f379342SAlexander V. Chernikov if (afdata == 0) { 8255f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 8265f379342SAlexander V. Chernikov } else { 8275f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 8285f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 8295f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 8305f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 8315f379342SAlexander V. Chernikov vtype = "unknown"; 8325f379342SAlexander V. Chernikov d.size = tainfo->size6; 8335f379342SAlexander V. Chernikov d.count = tainfo->count6; 8345f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 8355f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 8365f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 8375f379342SAlexander V. Chernikov } 8385f379342SAlexander V. Chernikov 839f1220db8SAlexander V. Chernikov return (0); 840f1220db8SAlexander V. Chernikov } 841f1220db8SAlexander V. Chernikov 842f1220db8SAlexander V. Chernikov 843f1220db8SAlexander V. Chernikov /* 844f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 845f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 846f1220db8SAlexander V. Chernikov */ 847f1220db8SAlexander V. Chernikov 848f1220db8SAlexander V. Chernikov static int 849f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 850f1220db8SAlexander V. Chernikov { 851f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 85281d3153dSAlexander V. Chernikov int error; 85310e3bebfSBryan Drewery int is_all; 85410e3bebfSBryan Drewery 85510e3bebfSBryan Drewery is_all = arg == NULL ? 0 : 1; 856f1220db8SAlexander V. Chernikov 857720ee730SAlexander V. Chernikov if ((error = table_do_get_list(i, &oh)) != 0) { 85881d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 85981d3153dSAlexander V. Chernikov return (error); 86081d3153dSAlexander V. Chernikov } 86181d3153dSAlexander V. Chernikov 8622b3d6647SBryan Drewery table_show_list(oh, is_all); 863f1220db8SAlexander V. Chernikov 864f1220db8SAlexander V. Chernikov free(oh); 865f1220db8SAlexander V. Chernikov return (0); 866f1220db8SAlexander V. Chernikov } 867f1220db8SAlexander V. Chernikov 868f1220db8SAlexander V. Chernikov static int 869f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 870f1220db8SAlexander V. Chernikov { 871ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 872f1220db8SAlexander V. Chernikov 873ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 874ac35ff17SAlexander V. Chernikov 875ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 876ac35ff17SAlexander V. Chernikov 877ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 878f1220db8SAlexander V. Chernikov } 879f1220db8SAlexander V. Chernikov 880ac35ff17SAlexander V. Chernikov static int 881ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 8823a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent, int count, int atomic) 883ac35ff17SAlexander V. Chernikov { 884db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 8853a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent_base; 8863a845e10SAlexander V. Chernikov caddr_t pbuf; 887db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 8883a845e10SAlexander V. Chernikov int error, i; 8893a845e10SAlexander V. Chernikov size_t sz; 890ac35ff17SAlexander V. Chernikov 8913a845e10SAlexander V. Chernikov sz = sizeof(*ctlv) + sizeof(*tent) * count; 8923a845e10SAlexander V. Chernikov if (count == 1) { 893ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 8943a845e10SAlexander V. Chernikov pbuf = xbuf; 8953a845e10SAlexander V. Chernikov } else { 8963a845e10SAlexander V. Chernikov if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) 8973a845e10SAlexander V. Chernikov return (ENOMEM); 8983a845e10SAlexander V. Chernikov } 8993a845e10SAlexander V. Chernikov 9003a845e10SAlexander V. Chernikov memcpy(pbuf, oh, sizeof(*oh)); 9013a845e10SAlexander V. Chernikov oh = (ipfw_obj_header *)pbuf; 902ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 903ac35ff17SAlexander V. Chernikov 904db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 9053a845e10SAlexander V. Chernikov ctlv->count = count; 9063a845e10SAlexander V. Chernikov ctlv->head.length = sz; 9073a845e10SAlexander V. Chernikov if (atomic != 0) 9083a845e10SAlexander V. Chernikov ctlv->flags |= IPFW_CTF_ATOMIC; 909db785d31SAlexander V. Chernikov 9103a845e10SAlexander V. Chernikov tent_base = tent; 9113a845e10SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent) * count); 912db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 9133a845e10SAlexander V. Chernikov for (i = 0; i < count; i++, tent++) { 914ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 9153a845e10SAlexander V. Chernikov tent->idx = oh->idx; 9163a845e10SAlexander V. Chernikov } 917ac35ff17SAlexander V. Chernikov 9183a845e10SAlexander V. Chernikov sz += sizeof(*oh); 9193a845e10SAlexander V. Chernikov error = do_get3(cmd, &oh->opheader, &sz); 920092f8ba3SAndrey V. Elsukov if (error != 0) 921092f8ba3SAndrey V. Elsukov error = errno; 9223a845e10SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 9233a845e10SAlexander V. Chernikov /* Copy result back to provided buffer */ 9243a845e10SAlexander V. Chernikov memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); 9253a845e10SAlexander V. Chernikov 9263a845e10SAlexander V. Chernikov if (pbuf != xbuf) 9273a845e10SAlexander V. Chernikov free(pbuf); 928ac35ff17SAlexander V. Chernikov 929ac35ff17SAlexander V. Chernikov return (error); 930ac35ff17SAlexander V. Chernikov } 931ac35ff17SAlexander V. Chernikov 932ac35ff17SAlexander V. Chernikov static void 9333a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, 9343a845e10SAlexander V. Chernikov int quiet, int update, int atomic) 935ac35ff17SAlexander V. Chernikov { 9363a845e10SAlexander V. Chernikov ipfw_obj_tentry *ptent, tent, *tent_buf; 93781d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 9380cba2b28SAlexander V. Chernikov uint8_t type; 9390cba2b28SAlexander V. Chernikov uint32_t vmask; 9403a845e10SAlexander V. Chernikov int cmd, count, error, i, ignored; 9413a845e10SAlexander V. Chernikov char *texterr, *etxt, *px; 942ac35ff17SAlexander V. Chernikov 943ac35ff17SAlexander V. Chernikov if (ac == 0) 944ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 945ac35ff17SAlexander V. Chernikov 946ac35ff17SAlexander V. Chernikov if (add != 0) { 947ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 9484c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 949ac35ff17SAlexander V. Chernikov } else { 950ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 9514c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 952ac35ff17SAlexander V. Chernikov } 953ac35ff17SAlexander V. Chernikov 9543a845e10SAlexander V. Chernikov /* 9553a845e10SAlexander V. Chernikov * Calculate number of entries: 9563a845e10SAlexander V. Chernikov * Assume [key val] x N for add 9573a845e10SAlexander V. Chernikov * and 9583a845e10SAlexander V. Chernikov * key x N for delete 9593a845e10SAlexander V. Chernikov */ 9603a845e10SAlexander V. Chernikov count = (add != 0) ? ac / 2 + 1 : ac; 9613a845e10SAlexander V. Chernikov 9623a845e10SAlexander V. Chernikov if (count <= 1) { 9633a845e10SAlexander V. Chernikov /* Adding single entry with/without value */ 9643a845e10SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 9653a845e10SAlexander V. Chernikov tent_buf = &tent; 9663a845e10SAlexander V. Chernikov } else { 9673a845e10SAlexander V. Chernikov 9683a845e10SAlexander V. Chernikov if ((tent_buf = calloc(count, sizeof(tent))) == NULL) 9693a845e10SAlexander V. Chernikov errx(EX_OSERR, 9703a845e10SAlexander V. Chernikov "Unable to allocate memory for all entries"); 9713a845e10SAlexander V. Chernikov } 9723a845e10SAlexander V. Chernikov ptent = tent_buf; 9733a845e10SAlexander V. Chernikov 9743a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 9753a845e10SAlexander V. Chernikov count = 0; 9763a845e10SAlexander V. Chernikov while (ac > 0) { 9770cba2b28SAlexander V. Chernikov tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi); 9783a845e10SAlexander V. Chernikov 9793a845e10SAlexander V. Chernikov /* 980463a577bSEitan Adler * Compatibility layer: auto-create table if not exists. 9813a845e10SAlexander V. Chernikov */ 9823a845e10SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 9833a845e10SAlexander V. Chernikov xi.type = type; 9840cba2b28SAlexander V. Chernikov xi.vmask = vmask; 9853a845e10SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, 9863a845e10SAlexander V. Chernikov sizeof(xi.tablename)); 987e62cd31fSAndrey V. Elsukov if (quiet == 0) 988e62cd31fSAndrey V. Elsukov warnx("DEPRECATED: inserting data into " 989e62cd31fSAndrey V. Elsukov "non-existent table %s. (auto-created)", 9903a845e10SAlexander V. Chernikov xi.tablename); 9913a845e10SAlexander V. Chernikov table_do_create(oh, &xi); 9923a845e10SAlexander V. Chernikov } 9933a845e10SAlexander V. Chernikov 9943a845e10SAlexander V. Chernikov oh->ntlv.type = type; 9953a845e10SAlexander V. Chernikov ac--; av++; 9963a845e10SAlexander V. Chernikov 9973a845e10SAlexander V. Chernikov if (add != 0 && ac > 0) { 9980cba2b28SAlexander V. Chernikov tentry_fill_value(oh, ptent, *av, type, vmask); 9993a845e10SAlexander V. Chernikov ac--; av++; 10003a845e10SAlexander V. Chernikov } 10013a845e10SAlexander V. Chernikov 10023a845e10SAlexander V. Chernikov if (update != 0) 10033a845e10SAlexander V. Chernikov ptent->head.flags |= IPFW_TF_UPDATE; 10043a845e10SAlexander V. Chernikov 10053a845e10SAlexander V. Chernikov count++; 10063a845e10SAlexander V. Chernikov ptent++; 10073a845e10SAlexander V. Chernikov } 10083a845e10SAlexander V. Chernikov 10093a845e10SAlexander V. Chernikov error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 10103a845e10SAlexander V. Chernikov 10113a845e10SAlexander V. Chernikov /* 10123a845e10SAlexander V. Chernikov * Compatibility stuff: do not yell on duplicate keys or 10133a845e10SAlexander V. Chernikov * failed deletions. 10143a845e10SAlexander V. Chernikov */ 10153a845e10SAlexander V. Chernikov if (error == 0 || (error == EEXIST && add != 0) || 10163a845e10SAlexander V. Chernikov (error == ENOENT && add == 0)) { 10173a845e10SAlexander V. Chernikov if (quiet != 0) { 10183a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10193a845e10SAlexander V. Chernikov free(tent_buf); 10203a845e10SAlexander V. Chernikov return; 10213a845e10SAlexander V. Chernikov } 10223a845e10SAlexander V. Chernikov } 10233a845e10SAlexander V. Chernikov 10243a845e10SAlexander V. Chernikov /* Report results back */ 10253a845e10SAlexander V. Chernikov ptent = tent_buf; 10263a845e10SAlexander V. Chernikov for (i = 0; i < count; ptent++, i++) { 10273a845e10SAlexander V. Chernikov ignored = 0; 10283a845e10SAlexander V. Chernikov switch (ptent->result) { 10293a845e10SAlexander V. Chernikov case IPFW_TR_ADDED: 10303a845e10SAlexander V. Chernikov px = "added"; 10313a845e10SAlexander V. Chernikov break; 10323a845e10SAlexander V. Chernikov case IPFW_TR_DELETED: 10333a845e10SAlexander V. Chernikov px = "deleted"; 10343a845e10SAlexander V. Chernikov break; 10353a845e10SAlexander V. Chernikov case IPFW_TR_UPDATED: 10363a845e10SAlexander V. Chernikov px = "updated"; 10373a845e10SAlexander V. Chernikov break; 10383a845e10SAlexander V. Chernikov case IPFW_TR_LIMIT: 10393a845e10SAlexander V. Chernikov px = "limit"; 10403a845e10SAlexander V. Chernikov ignored = 1; 10413a845e10SAlexander V. Chernikov break; 10423a845e10SAlexander V. Chernikov case IPFW_TR_ERROR: 10433a845e10SAlexander V. Chernikov px = "error"; 10443a845e10SAlexander V. Chernikov ignored = 1; 10453a845e10SAlexander V. Chernikov break; 10463a845e10SAlexander V. Chernikov case IPFW_TR_NOTFOUND: 10473a845e10SAlexander V. Chernikov px = "notfound"; 10483a845e10SAlexander V. Chernikov ignored = 1; 10493a845e10SAlexander V. Chernikov break; 10503a845e10SAlexander V. Chernikov case IPFW_TR_EXISTS: 10513a845e10SAlexander V. Chernikov px = "exists"; 10523a845e10SAlexander V. Chernikov ignored = 1; 10533a845e10SAlexander V. Chernikov break; 10543a845e10SAlexander V. Chernikov case IPFW_TR_IGNORED: 10553a845e10SAlexander V. Chernikov px = "ignored"; 10563a845e10SAlexander V. Chernikov ignored = 1; 10573a845e10SAlexander V. Chernikov break; 10583a845e10SAlexander V. Chernikov default: 10593a845e10SAlexander V. Chernikov px = "unknown"; 10603a845e10SAlexander V. Chernikov ignored = 1; 10613a845e10SAlexander V. Chernikov } 10623a845e10SAlexander V. Chernikov 10633a845e10SAlexander V. Chernikov if (error != 0 && atomic != 0 && ignored == 0) 10643a845e10SAlexander V. Chernikov printf("%s(reverted): ", px); 10653a845e10SAlexander V. Chernikov else 10663a845e10SAlexander V. Chernikov printf("%s: ", px); 10673a845e10SAlexander V. Chernikov 10683a845e10SAlexander V. Chernikov table_show_entry(&xi, ptent); 10693a845e10SAlexander V. Chernikov } 10703a845e10SAlexander V. Chernikov 10713a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10723a845e10SAlexander V. Chernikov free(tent_buf); 10733a845e10SAlexander V. Chernikov 10743a845e10SAlexander V. Chernikov if (error == 0) 10754c0c07a5SAlexander V. Chernikov return; 107668bde59eSAlexander V. Chernikov /* Get real OS error */ 107768bde59eSAlexander V. Chernikov error = errno; 10784c0c07a5SAlexander V. Chernikov 10794c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 10804c0c07a5SAlexander V. Chernikov switch (error) { 10814c0c07a5SAlexander V. Chernikov case EEXIST: 10824c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 10834c0c07a5SAlexander V. Chernikov break; 10844c0c07a5SAlexander V. Chernikov case EFBIG: 10854c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 10864c0c07a5SAlexander V. Chernikov break; 10874c0c07a5SAlexander V. Chernikov case ESRCH: 10884c0c07a5SAlexander V. Chernikov etxt = "table not found"; 10894c0c07a5SAlexander V. Chernikov break; 10904c0c07a5SAlexander V. Chernikov case ENOENT: 10914c0c07a5SAlexander V. Chernikov etxt = "record not found"; 10924c0c07a5SAlexander V. Chernikov break; 10934f43138aSAlexander V. Chernikov case EACCES: 10944f43138aSAlexander V. Chernikov etxt = "table is locked"; 10954f43138aSAlexander V. Chernikov break; 10964c0c07a5SAlexander V. Chernikov default: 10974c0c07a5SAlexander V. Chernikov etxt = strerror(error); 10984c0c07a5SAlexander V. Chernikov } 10994c0c07a5SAlexander V. Chernikov 11004c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 1101ac35ff17SAlexander V. Chernikov } 1102ac35ff17SAlexander V. Chernikov 110381d3153dSAlexander V. Chernikov static int 110481d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 110581d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 110681d3153dSAlexander V. Chernikov { 110781d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 110881d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 11090cba2b28SAlexander V. Chernikov uint8_t type; 11100cba2b28SAlexander V. Chernikov uint32_t vmask; 111181d3153dSAlexander V. Chernikov size_t sz; 111281d3153dSAlexander V. Chernikov 111381d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 111481d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 111581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 111681d3153dSAlexander V. Chernikov 111781d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 111881d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 111981d3153dSAlexander V. Chernikov tent->idx = 1; 112081d3153dSAlexander V. Chernikov 11210cba2b28SAlexander V. Chernikov tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); 112281d3153dSAlexander V. Chernikov oh->ntlv.type = type; 112381d3153dSAlexander V. Chernikov 112481d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 1125b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0) 1126b6462881SAlexander V. Chernikov return (errno); 112781d3153dSAlexander V. Chernikov 112881d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 112981d3153dSAlexander V. Chernikov return (EINVAL); 113081d3153dSAlexander V. Chernikov 113181d3153dSAlexander V. Chernikov *xtent = *tent; 113281d3153dSAlexander V. Chernikov 113381d3153dSAlexander V. Chernikov return (0); 113481d3153dSAlexander V. Chernikov } 113581d3153dSAlexander V. Chernikov 113681d3153dSAlexander V. Chernikov static void 113781d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 113881d3153dSAlexander V. Chernikov { 113981d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 114081d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 1141914bffb6SAlexander V. Chernikov char key[64]; 114281d3153dSAlexander V. Chernikov int error; 114381d3153dSAlexander V. Chernikov 114481d3153dSAlexander V. Chernikov if (ac == 0) 114581d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 114681d3153dSAlexander V. Chernikov 1147914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 1148914bffb6SAlexander V. Chernikov 11493a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 1150914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 115181d3153dSAlexander V. Chernikov 115281d3153dSAlexander V. Chernikov switch (error) { 115381d3153dSAlexander V. Chernikov case 0: 115481d3153dSAlexander V. Chernikov break; 115581d3153dSAlexander V. Chernikov case ESRCH: 115681d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 115781d3153dSAlexander V. Chernikov case ENOENT: 115881d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 115981d3153dSAlexander V. Chernikov case ENOTSUP: 116081d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 116181d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 116281d3153dSAlexander V. Chernikov default: 116381d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 116481d3153dSAlexander V. Chernikov } 116581d3153dSAlexander V. Chernikov 116681d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 116781d3153dSAlexander V. Chernikov } 1168ac35ff17SAlexander V. Chernikov 1169ac35ff17SAlexander V. Chernikov static void 1170914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1171914bffb6SAlexander V. Chernikov uint8_t tflags) 1172ac35ff17SAlexander V. Chernikov { 1173914bffb6SAlexander V. Chernikov char *p, *pp; 1174ac35ff17SAlexander V. Chernikov int mask, af; 1175914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 1176914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 1177ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 1178914bffb6SAlexander V. Chernikov uint16_t port; 1179914bffb6SAlexander V. Chernikov struct protoent *pent; 1180914bffb6SAlexander V. Chernikov struct servent *sent; 1181ac35ff17SAlexander V. Chernikov int masklen; 1182ac35ff17SAlexander V. Chernikov 1183ac35ff17SAlexander V. Chernikov masklen = 0; 1184ac35ff17SAlexander V. Chernikov af = 0; 1185ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 1186ac35ff17SAlexander V. Chernikov 1187ac35ff17SAlexander V. Chernikov switch (type) { 1188c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1189ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 1190ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 1191ac35ff17SAlexander V. Chernikov *p = '\0'; 1192ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 1193ac35ff17SAlexander V. Chernikov } 1194ac35ff17SAlexander V. Chernikov 1195ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 1196ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 1197ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 1198ac35ff17SAlexander V. Chernikov p + 1); 1199ac35ff17SAlexander V. Chernikov 1200ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 1201ac35ff17SAlexander V. Chernikov af = AF_INET; 1202ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 1203ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 1204ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 1205ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 1206ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 1207ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 1208ac35ff17SAlexander V. Chernikov p + 1); 1209ac35ff17SAlexander V. Chernikov 1210ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 1211ac35ff17SAlexander V. Chernikov af = AF_INET6; 1212ac35ff17SAlexander V. Chernikov } else { 1213ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 1214ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1215ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1216ac35ff17SAlexander V. Chernikov 1217ac35ff17SAlexander V. Chernikov masklen = 32; 1218c21034b7SAlexander V. Chernikov type = IPFW_TABLE_ADDR; 1219ac35ff17SAlexander V. Chernikov af = AF_INET; 1220ac35ff17SAlexander V. Chernikov } 1221ac35ff17SAlexander V. Chernikov break; 1222ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1223ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 1224ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1225ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 1226ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 1227ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 1228ac35ff17SAlexander V. Chernikov break; 1229b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1230ac35ff17SAlexander V. Chernikov /* Port or any other key */ 1231ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 1232ac35ff17SAlexander V. Chernikov if (*p != '\0') 1233ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 1234ac35ff17SAlexander V. Chernikov 1235ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 1236ac35ff17SAlexander V. Chernikov *pkey = key; 1237ac35ff17SAlexander V. Chernikov masklen = 32; 1238ac35ff17SAlexander V. Chernikov break; 1239914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1240914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1241914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 1242914bffb6SAlexander V. Chernikov af = 0; 1243914bffb6SAlexander V. Chernikov 1244914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6> */ 1245914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1246914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1247914bffb6SAlexander V. Chernikov *p++ = '\0'; 1248914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1249914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1250914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1251914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1252914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1253914bffb6SAlexander V. Chernikov af = AF_INET; 1254914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 1255914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1256914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1257914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1258914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1259914bffb6SAlexander V. Chernikov af = AF_INET6; 1260914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 1261914bffb6SAlexander V. Chernikov } 1262914bffb6SAlexander V. Chernikov 1263914bffb6SAlexander V. Chernikov arg = p; 1264914bffb6SAlexander V. Chernikov } 1265914bffb6SAlexander V. Chernikov 1266914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 1267914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 126835df97d0SAlexander V. Chernikov if (arg == NULL) 126935df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: proto missing"); 1270914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1271914bffb6SAlexander V. Chernikov *p++ = '\0'; 1272914bffb6SAlexander V. Chernikov 1273914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 1274914bffb6SAlexander V. Chernikov if (*pp != '\0') { 1275914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 1276914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 1277914bffb6SAlexander V. Chernikov arg); 1278914bffb6SAlexander V. Chernikov else 1279914bffb6SAlexander V. Chernikov key = pent->p_proto; 1280914bffb6SAlexander V. Chernikov } 1281914bffb6SAlexander V. Chernikov 1282914bffb6SAlexander V. Chernikov if (key > 255) 1283914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 1284914bffb6SAlexander V. Chernikov 1285914bffb6SAlexander V. Chernikov tfe->proto = key; 1286914bffb6SAlexander V. Chernikov 1287914bffb6SAlexander V. Chernikov arg = p; 1288914bffb6SAlexander V. Chernikov } 1289914bffb6SAlexander V. Chernikov 1290914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1291914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 129235df97d0SAlexander V. Chernikov if (arg == NULL) 129335df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: src port missing"); 1294914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1295914bffb6SAlexander V. Chernikov *p++ = '\0'; 1296914bffb6SAlexander V. Chernikov 129752772a85SAndrey V. Elsukov port = htons(strtol(arg, &pp, 10)); 129852772a85SAndrey V. Elsukov if (*pp != '\0') { 1299914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1300914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1301914bffb6SAlexander V. Chernikov arg); 130252772a85SAndrey V. Elsukov port = sent->s_port; 1303914bffb6SAlexander V. Chernikov } 1304914bffb6SAlexander V. Chernikov tfe->sport = port; 1305914bffb6SAlexander V. Chernikov arg = p; 1306914bffb6SAlexander V. Chernikov } 1307914bffb6SAlexander V. Chernikov 1308914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1309914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 131035df97d0SAlexander V. Chernikov if (arg == NULL) 131135df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst ip missing"); 1312914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1313914bffb6SAlexander V. Chernikov *p++ = '\0'; 1314914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1315914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1316914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1317914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1318914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1319914bffb6SAlexander V. Chernikov af = AF_INET; 1320914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 1321914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1322914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1323914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1324914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1325914bffb6SAlexander V. Chernikov af = AF_INET6; 1326914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1327914bffb6SAlexander V. Chernikov } 1328914bffb6SAlexander V. Chernikov 1329914bffb6SAlexander V. Chernikov arg = p; 1330914bffb6SAlexander V. Chernikov } 1331914bffb6SAlexander V. Chernikov 1332914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1333914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 133435df97d0SAlexander V. Chernikov if (arg == NULL) 133535df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst port missing"); 1336914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1337914bffb6SAlexander V. Chernikov *p++ = '\0'; 1338914bffb6SAlexander V. Chernikov 133952772a85SAndrey V. Elsukov port = htons(strtol(arg, &pp, 10)); 134052772a85SAndrey V. Elsukov if (*pp != '\0') { 1341914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1342914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1343914bffb6SAlexander V. Chernikov arg); 134452772a85SAndrey V. Elsukov port = sent->s_port; 1345914bffb6SAlexander V. Chernikov } 1346914bffb6SAlexander V. Chernikov tfe->dport = port; 1347914bffb6SAlexander V. Chernikov arg = p; 1348914bffb6SAlexander V. Chernikov } 1349914bffb6SAlexander V. Chernikov 1350914bffb6SAlexander V. Chernikov tfe->af = af; 1351914bffb6SAlexander V. Chernikov 1352914bffb6SAlexander V. Chernikov break; 1353914bffb6SAlexander V. Chernikov 1354ac35ff17SAlexander V. Chernikov default: 1355ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1356ac35ff17SAlexander V. Chernikov } 1357ac35ff17SAlexander V. Chernikov 1358ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1359ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1360ac35ff17SAlexander V. Chernikov } 1361ac35ff17SAlexander V. Chernikov 13628755aff6SAlexander V. Chernikov /* 13638755aff6SAlexander V. Chernikov * Tries to guess table key type. 13648755aff6SAlexander V. Chernikov * This procedure is used in legacy table auto-create 13658755aff6SAlexander V. Chernikov * code AND in `ipfw -n` ruleset checking. 13668755aff6SAlexander V. Chernikov * 13678755aff6SAlexander V. Chernikov * Imported from old table_fill_xentry() parse code. 13688755aff6SAlexander V. Chernikov */ 13698755aff6SAlexander V. Chernikov static int 13708755aff6SAlexander V. Chernikov guess_key_type(char *key, uint8_t *ptype) 13718755aff6SAlexander V. Chernikov { 13728755aff6SAlexander V. Chernikov char *p; 13738755aff6SAlexander V. Chernikov struct in6_addr addr; 13748755aff6SAlexander V. Chernikov uint32_t kv; 13758755aff6SAlexander V. Chernikov 13768755aff6SAlexander V. Chernikov if (ishexnumber(*key) != 0 || *key == ':') { 13778755aff6SAlexander V. Chernikov /* Remove / if exists */ 13788755aff6SAlexander V. Chernikov if ((p = strchr(key, '/')) != NULL) 13798755aff6SAlexander V. Chernikov *p = '\0'; 13808755aff6SAlexander V. Chernikov 13818755aff6SAlexander V. Chernikov if ((inet_pton(AF_INET, key, &addr) == 1) || 13828755aff6SAlexander V. Chernikov (inet_pton(AF_INET6, key, &addr) == 1)) { 13838755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 13848755aff6SAlexander V. Chernikov if (p != NULL) 13858755aff6SAlexander V. Chernikov *p = '/'; 13868755aff6SAlexander V. Chernikov return (0); 13878755aff6SAlexander V. Chernikov } else { 13888755aff6SAlexander V. Chernikov /* Port or any other key */ 13898755aff6SAlexander V. Chernikov /* Skip non-base 10 entries like 'fa1' */ 13908755aff6SAlexander V. Chernikov kv = strtol(key, &p, 10); 13918755aff6SAlexander V. Chernikov if (*p == '\0') { 13928755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 13938755aff6SAlexander V. Chernikov return (0); 13948755aff6SAlexander V. Chernikov } else if ((p != key) && (*p == '.')) { 13958755aff6SAlexander V. Chernikov /* 13968755aff6SAlexander V. Chernikov * Warn on IPv4 address strings 13978755aff6SAlexander V. Chernikov * which are "valid" for inet_aton() but not 13988755aff6SAlexander V. Chernikov * in inet_pton(). 13998755aff6SAlexander V. Chernikov * 14008755aff6SAlexander V. Chernikov * Typical examples: '10.5' or '10.0.0.05' 14018755aff6SAlexander V. Chernikov */ 14028755aff6SAlexander V. Chernikov return (1); 14038755aff6SAlexander V. Chernikov } 14048755aff6SAlexander V. Chernikov } 14058755aff6SAlexander V. Chernikov } 14068755aff6SAlexander V. Chernikov 14078755aff6SAlexander V. Chernikov if (strchr(key, '.') == NULL) { 14088755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 14098755aff6SAlexander V. Chernikov return (0); 14108755aff6SAlexander V. Chernikov } 14118755aff6SAlexander V. Chernikov 14128755aff6SAlexander V. Chernikov if (lookup_host(key, (struct in_addr *)&addr) != 0) 14138755aff6SAlexander V. Chernikov return (1); 14148755aff6SAlexander V. Chernikov 14158755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 14168755aff6SAlexander V. Chernikov return (0); 14178755aff6SAlexander V. Chernikov } 14188755aff6SAlexander V. Chernikov 1419ac35ff17SAlexander V. Chernikov static void 1420ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 14210cba2b28SAlexander V. Chernikov int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) 1422ac35ff17SAlexander V. Chernikov { 14230cba2b28SAlexander V. Chernikov uint8_t type, tflags; 14240cba2b28SAlexander V. Chernikov uint32_t vmask; 1425ac35ff17SAlexander V. Chernikov int error; 1426ac35ff17SAlexander V. Chernikov 1427ac35ff17SAlexander V. Chernikov type = 0; 1428914bffb6SAlexander V. Chernikov tflags = 0; 14290cba2b28SAlexander V. Chernikov vmask = 0; 1430ac35ff17SAlexander V. Chernikov 14313a845e10SAlexander V. Chernikov if (xi->tablename[0] == '\0') 143281d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 14333a845e10SAlexander V. Chernikov else 14343a845e10SAlexander V. Chernikov error = 0; 143581d3153dSAlexander V. Chernikov 143681d3153dSAlexander V. Chernikov if (error == 0) { 14378755aff6SAlexander V. Chernikov if (co.test_only == 0) { 14388755aff6SAlexander V. Chernikov /* Table found */ 143981d3153dSAlexander V. Chernikov type = xi->type; 1440914bffb6SAlexander V. Chernikov tflags = xi->tflags; 14410cba2b28SAlexander V. Chernikov vmask = xi->vmask; 144281d3153dSAlexander V. Chernikov } else { 14438755aff6SAlexander V. Chernikov /* 1444463a577bSEitan Adler * We're running `ipfw -n` 1445463a577bSEitan Adler * Compatibility layer: try to guess key type 14468755aff6SAlexander V. Chernikov * before failing. 14478755aff6SAlexander V. Chernikov */ 14488755aff6SAlexander V. Chernikov if (guess_key_type(key, &type) != 0) { 14498755aff6SAlexander V. Chernikov /* Inknown key */ 14508755aff6SAlexander V. Chernikov errx(EX_USAGE, "Cannot guess " 14518755aff6SAlexander V. Chernikov "key '%s' type", key); 14528755aff6SAlexander V. Chernikov } 14538755aff6SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 14548755aff6SAlexander V. Chernikov } 14558755aff6SAlexander V. Chernikov } else { 145681d3153dSAlexander V. Chernikov if (error != ESRCH) 145781d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 145881d3153dSAlexander V. Chernikov oh->ntlv.name); 145935df97d0SAlexander V. Chernikov if (add == 0) 146035df97d0SAlexander V. Chernikov errx(EX_DATAERR, "Table %s does not exist", 146135df97d0SAlexander V. Chernikov oh->ntlv.name); 1462ac35ff17SAlexander V. Chernikov /* 14638755aff6SAlexander V. Chernikov * Table does not exist 1464463a577bSEitan Adler * Compatibility layer: try to guess key type before failing. 1465ac35ff17SAlexander V. Chernikov */ 14668755aff6SAlexander V. Chernikov if (guess_key_type(key, &type) != 0) { 146781d3153dSAlexander V. Chernikov /* Inknown key */ 146881d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1469db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 147081d3153dSAlexander V. Chernikov } 14718755aff6SAlexander V. Chernikov 14728755aff6SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 1473ac35ff17SAlexander V. Chernikov } 1474ac35ff17SAlexander V. Chernikov 1475914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1476ac35ff17SAlexander V. Chernikov 1477ac35ff17SAlexander V. Chernikov *ptype = type; 14780cba2b28SAlexander V. Chernikov *pvmask = vmask; 14790cba2b28SAlexander V. Chernikov } 14800cba2b28SAlexander V. Chernikov 14810cba2b28SAlexander V. Chernikov static void 14820cba2b28SAlexander V. Chernikov set_legacy_value(uint32_t val, ipfw_table_value *v) 14830cba2b28SAlexander V. Chernikov { 14840cba2b28SAlexander V. Chernikov v->tag = val; 14850cba2b28SAlexander V. Chernikov v->pipe = val; 14860cba2b28SAlexander V. Chernikov v->divert = val; 14870cba2b28SAlexander V. Chernikov v->skipto = val; 14880cba2b28SAlexander V. Chernikov v->netgraph = val; 14890cba2b28SAlexander V. Chernikov v->fib = val; 14900cba2b28SAlexander V. Chernikov v->nat = val; 14910cba2b28SAlexander V. Chernikov v->nh4 = val; 14920cba2b28SAlexander V. Chernikov v->dscp = (uint8_t)val; 14930cba2b28SAlexander V. Chernikov v->limit = val; 1494ac35ff17SAlexander V. Chernikov } 1495ac35ff17SAlexander V. Chernikov 1496ac35ff17SAlexander V. Chernikov static void 1497ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 14980cba2b28SAlexander V. Chernikov uint8_t type, uint32_t vmask) 1499ac35ff17SAlexander V. Chernikov { 15002530ed9eSAndrey V. Elsukov struct addrinfo hints, *res; 1501b7684f4bSMarcelo Araujo uint32_t a4, flag, val; 15020cba2b28SAlexander V. Chernikov ipfw_table_value *v; 15030cba2b28SAlexander V. Chernikov uint32_t i; 1504d91c61c3SAlexander V. Chernikov int dval; 15050cba2b28SAlexander V. Chernikov char *comma, *e, *etype, *n, *p; 15064e0a8b61SConrad Meyer struct in_addr ipaddr; 1507ac35ff17SAlexander V. Chernikov 15080cba2b28SAlexander V. Chernikov v = &tent->v.value; 15090cba2b28SAlexander V. Chernikov 15100cba2b28SAlexander V. Chernikov /* Compat layer: keep old behavior for legacy value types */ 15110cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 1512adf3b2b9SAlexander V. Chernikov /* Try to interpret as number first */ 15130cba2b28SAlexander V. Chernikov val = strtoul(arg, &p, 0); 15140cba2b28SAlexander V. Chernikov if (*p == '\0') { 15150cba2b28SAlexander V. Chernikov set_legacy_value(val, v); 1516adf3b2b9SAlexander V. Chernikov return; 15170cba2b28SAlexander V. Chernikov } 1518adf3b2b9SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &val) == 1) { 15190cba2b28SAlexander V. Chernikov set_legacy_value(ntohl(val), v); 1520adf3b2b9SAlexander V. Chernikov return; 1521adf3b2b9SAlexander V. Chernikov } 1522adf3b2b9SAlexander V. Chernikov /* Try hostname */ 15234e0a8b61SConrad Meyer if (lookup_host(arg, &ipaddr) == 0) { 15244e0a8b61SConrad Meyer set_legacy_value(ntohl(ipaddr.s_addr), v); 1525adf3b2b9SAlexander V. Chernikov return; 15260cba2b28SAlexander V. Chernikov } 1527adf3b2b9SAlexander V. Chernikov errx(EX_OSERR, "Unable to parse value %s", arg); 15280cba2b28SAlexander V. Chernikov } 15290cba2b28SAlexander V. Chernikov 15300cba2b28SAlexander V. Chernikov /* 15310cba2b28SAlexander V. Chernikov * Shorthands: handle single value if vmask consists 15320cba2b28SAlexander V. Chernikov * of numbers only. e.g.: 15330cba2b28SAlexander V. Chernikov * vmask = "fib,skipto" -> treat input "1" as "1,1" 15340cba2b28SAlexander V. Chernikov */ 15350cba2b28SAlexander V. Chernikov 15360cba2b28SAlexander V. Chernikov n = arg; 15370cba2b28SAlexander V. Chernikov etype = NULL; 15380cba2b28SAlexander V. Chernikov for (i = 1; i < (1 << 31); i *= 2) { 15390cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 15400cba2b28SAlexander V. Chernikov continue; 15410cba2b28SAlexander V. Chernikov vmask &= ~flag; 15420cba2b28SAlexander V. Chernikov 15430cba2b28SAlexander V. Chernikov if ((comma = strchr(n, ',')) != NULL) 15440cba2b28SAlexander V. Chernikov *comma = '\0'; 15450cba2b28SAlexander V. Chernikov 15460cba2b28SAlexander V. Chernikov switch (flag) { 15470cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 15480cba2b28SAlexander V. Chernikov v->tag = strtol(n, &e, 10); 15490cba2b28SAlexander V. Chernikov if (*e != '\0') 15500cba2b28SAlexander V. Chernikov etype = "tag"; 1551ac35ff17SAlexander V. Chernikov break; 15520cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 15530cba2b28SAlexander V. Chernikov v->pipe = strtol(n, &e, 10); 15540cba2b28SAlexander V. Chernikov if (*e != '\0') 15550cba2b28SAlexander V. Chernikov etype = "pipe"; 1556ac35ff17SAlexander V. Chernikov break; 15570cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 15580cba2b28SAlexander V. Chernikov v->divert = strtol(n, &e, 10); 15590cba2b28SAlexander V. Chernikov if (*e != '\0') 15600cba2b28SAlexander V. Chernikov etype = "divert"; 15610cba2b28SAlexander V. Chernikov break; 15620cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 15630cba2b28SAlexander V. Chernikov v->skipto = strtol(n, &e, 10); 15640cba2b28SAlexander V. Chernikov if (*e != '\0') 15650cba2b28SAlexander V. Chernikov etype = "skipto"; 15660cba2b28SAlexander V. Chernikov break; 15670cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 15680cba2b28SAlexander V. Chernikov v->netgraph = strtol(n, &e, 10); 15690cba2b28SAlexander V. Chernikov if (*e != '\0') 15700cba2b28SAlexander V. Chernikov etype = "netgraph"; 15710cba2b28SAlexander V. Chernikov break; 15720cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 15730cba2b28SAlexander V. Chernikov v->fib = strtol(n, &e, 10); 15740cba2b28SAlexander V. Chernikov if (*e != '\0') 15750cba2b28SAlexander V. Chernikov etype = "fib"; 15760cba2b28SAlexander V. Chernikov break; 15770cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 15780cba2b28SAlexander V. Chernikov v->nat = strtol(n, &e, 10); 15790cba2b28SAlexander V. Chernikov if (*e != '\0') 15800cba2b28SAlexander V. Chernikov etype = "nat"; 15810cba2b28SAlexander V. Chernikov break; 15820cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 15830cba2b28SAlexander V. Chernikov v->limit = strtol(n, &e, 10); 15840cba2b28SAlexander V. Chernikov if (*e != '\0') 15850cba2b28SAlexander V. Chernikov etype = "limit"; 15860cba2b28SAlexander V. Chernikov break; 15870cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 15880cba2b28SAlexander V. Chernikov if (strchr(n, '.') != NULL && 15890cba2b28SAlexander V. Chernikov inet_pton(AF_INET, n, &a4) == 1) { 15900cba2b28SAlexander V. Chernikov v->nh4 = ntohl(a4); 15910cba2b28SAlexander V. Chernikov break; 15920cba2b28SAlexander V. Chernikov } 15934e0a8b61SConrad Meyer if (lookup_host(n, &ipaddr) == 0) { 15944e0a8b61SConrad Meyer v->nh4 = ntohl(ipaddr.s_addr); 15950cba2b28SAlexander V. Chernikov break; 15964e0a8b61SConrad Meyer } 15970cba2b28SAlexander V. Chernikov etype = "ipv4"; 1598ac35ff17SAlexander V. Chernikov break; 1599ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 16000cba2b28SAlexander V. Chernikov if (isalpha(*n)) { 1601d91c61c3SAlexander V. Chernikov if ((dval = match_token(f_ipdscp, n)) != -1) { 1602d91c61c3SAlexander V. Chernikov v->dscp = dval; 1603ac35ff17SAlexander V. Chernikov break; 1604d91c61c3SAlexander V. Chernikov } else 16050cba2b28SAlexander V. Chernikov etype = "DSCP code"; 16060cba2b28SAlexander V. Chernikov } else { 16070cba2b28SAlexander V. Chernikov v->dscp = strtol(n, &e, 10); 16080cba2b28SAlexander V. Chernikov if (v->dscp > 63 || *e != '\0') 16090cba2b28SAlexander V. Chernikov etype = "DSCP value"; 1610ac35ff17SAlexander V. Chernikov } 16110cba2b28SAlexander V. Chernikov break; 16120cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 16132530ed9eSAndrey V. Elsukov if (strchr(n, ':') != NULL) { 16142530ed9eSAndrey V. Elsukov memset(&hints, 0, sizeof(hints)); 16152530ed9eSAndrey V. Elsukov hints.ai_family = AF_INET6; 16162530ed9eSAndrey V. Elsukov hints.ai_flags = AI_NUMERICHOST; 16172530ed9eSAndrey V. Elsukov if (getaddrinfo(n, NULL, &hints, &res) == 0) { 16182530ed9eSAndrey V. Elsukov v->nh6 = ((struct sockaddr_in6 *) 16192530ed9eSAndrey V. Elsukov res->ai_addr)->sin6_addr; 16202530ed9eSAndrey V. Elsukov v->zoneid = ((struct sockaddr_in6 *) 16212530ed9eSAndrey V. Elsukov res->ai_addr)->sin6_scope_id; 16222530ed9eSAndrey V. Elsukov freeaddrinfo(res); 16230cba2b28SAlexander V. Chernikov break; 16242530ed9eSAndrey V. Elsukov } 16252530ed9eSAndrey V. Elsukov } 16260cba2b28SAlexander V. Chernikov etype = "ipv6"; 16270cba2b28SAlexander V. Chernikov break; 16280cba2b28SAlexander V. Chernikov } 16290cba2b28SAlexander V. Chernikov 16300cba2b28SAlexander V. Chernikov if (etype != NULL) 16310cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Unable to parse %s as %s", n, etype); 16320cba2b28SAlexander V. Chernikov 16330cba2b28SAlexander V. Chernikov if (comma != NULL) 16340cba2b28SAlexander V. Chernikov *comma++ = ','; 16350cba2b28SAlexander V. Chernikov 16360cba2b28SAlexander V. Chernikov if ((n = comma) != NULL) 16370cba2b28SAlexander V. Chernikov continue; 16380cba2b28SAlexander V. Chernikov 16390cba2b28SAlexander V. Chernikov /* End of input. */ 16400cba2b28SAlexander V. Chernikov if (vmask != 0) 16410cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Not enough fields inside value"); 16420cba2b28SAlexander V. Chernikov } 1643ac35ff17SAlexander V. Chernikov } 1644f1220db8SAlexander V. Chernikov 1645f1220db8SAlexander V. Chernikov /* 1646f1220db8SAlexander V. Chernikov * Compare table names. 1647f1220db8SAlexander V. Chernikov * Honor number comparison. 1648f1220db8SAlexander V. Chernikov */ 1649f1220db8SAlexander V. Chernikov static int 1650f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1651f1220db8SAlexander V. Chernikov { 1652f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1653f1220db8SAlexander V. Chernikov 1654f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1655f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1656f1220db8SAlexander V. Chernikov 165768394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1658f1220db8SAlexander V. Chernikov } 1659f1220db8SAlexander V. Chernikov 1660f1220db8SAlexander V. Chernikov /* 1661f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1662f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1663f1220db8SAlexander V. Chernikov * Returns 0 on success. 1664f1220db8SAlexander V. Chernikov */ 1665f1220db8SAlexander V. Chernikov static int 1666f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1667f1220db8SAlexander V. Chernikov { 166828ea4fa3SAlexander V. Chernikov ipfw_obj_lheader *olh; 1669f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1670f1220db8SAlexander V. Chernikov size_t sz; 1671f1220db8SAlexander V. Chernikov int i, error; 1672f1220db8SAlexander V. Chernikov 167328ea4fa3SAlexander V. Chernikov /* Start with reasonable default */ 167428ea4fa3SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1675f1220db8SAlexander V. Chernikov 167628ea4fa3SAlexander V. Chernikov for (;;) { 1677f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1678f1220db8SAlexander V. Chernikov return (ENOMEM); 1679f1220db8SAlexander V. Chernikov 1680f1220db8SAlexander V. Chernikov olh->size = sz; 1681b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) { 168228ea4fa3SAlexander V. Chernikov sz = olh->size; 168368bde59eSAlexander V. Chernikov free(olh); 168468bde59eSAlexander V. Chernikov if (errno != ENOMEM) 1685b6462881SAlexander V. Chernikov return (errno); 168668bde59eSAlexander V. Chernikov continue; 1687f1220db8SAlexander V. Chernikov } 1688f1220db8SAlexander V. Chernikov 1689f1220db8SAlexander V. Chernikov if (sort != 0) 1690e028ccdaSAndrey V. Elsukov qsort(olh + 1, olh->count, olh->objsize, 1691e028ccdaSAndrey V. Elsukov tablename_cmp); 1692f1220db8SAlexander V. Chernikov 1693f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1694f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1695e028ccdaSAndrey V. Elsukov if (co.use_set == 0 || info->set == co.use_set - 1) 1696e028ccdaSAndrey V. Elsukov error = f(info, arg); 1697e028ccdaSAndrey V. Elsukov info = (ipfw_xtable_info *)((caddr_t)info + 1698e028ccdaSAndrey V. Elsukov olh->objsize); 1699f1220db8SAlexander V. Chernikov } 1700f1220db8SAlexander V. Chernikov free(olh); 170128ea4fa3SAlexander V. Chernikov break; 170228ea4fa3SAlexander V. Chernikov } 1703f1220db8SAlexander V. Chernikov return (0); 1704f1220db8SAlexander V. Chernikov } 1705f1220db8SAlexander V. Chernikov 170628ea4fa3SAlexander V. Chernikov 1707f1220db8SAlexander V. Chernikov /* 1708f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1709720ee730SAlexander V. Chernikov * eXtended format. Allocate buffer large enough 1710720ee730SAlexander V. Chernikov * to store result. Called needs to free it later. 1711f1220db8SAlexander V. Chernikov * 1712f1220db8SAlexander V. Chernikov * Returns 0 on success. 1713f1220db8SAlexander V. Chernikov */ 1714f1220db8SAlexander V. Chernikov static int 1715720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1716f1220db8SAlexander V. Chernikov { 1717720ee730SAlexander V. Chernikov ipfw_obj_header *oh; 1718f1220db8SAlexander V. Chernikov size_t sz; 1719b6462881SAlexander V. Chernikov int c; 1720f1220db8SAlexander V. Chernikov 172181d3153dSAlexander V. Chernikov sz = 0; 1722720ee730SAlexander V. Chernikov oh = NULL; 1723720ee730SAlexander V. Chernikov for (c = 0; c < 8; c++) { 172481d3153dSAlexander V. Chernikov if (sz < i->size) 1725720ee730SAlexander V. Chernikov sz = i->size + 44; 1726720ee730SAlexander V. Chernikov if (oh != NULL) 1727720ee730SAlexander V. Chernikov free(oh); 1728720ee730SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1729720ee730SAlexander V. Chernikov continue; 1730720ee730SAlexander V. Chernikov table_fill_objheader(oh, i); 1731d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 1732b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) { 1733720ee730SAlexander V. Chernikov *poh = oh; 1734720ee730SAlexander V. Chernikov return (0); 173581d3153dSAlexander V. Chernikov } 1736f1220db8SAlexander V. Chernikov 1737b6462881SAlexander V. Chernikov if (errno != ENOMEM) 1738720ee730SAlexander V. Chernikov break; 1739720ee730SAlexander V. Chernikov } 1740720ee730SAlexander V. Chernikov free(oh); 1741720ee730SAlexander V. Chernikov 1742b6462881SAlexander V. Chernikov return (errno); 1743f1220db8SAlexander V. Chernikov } 1744f1220db8SAlexander V. Chernikov 1745f1220db8SAlexander V. Chernikov /* 1746f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1747f1220db8SAlexander V. Chernikov */ 1748f1220db8SAlexander V. Chernikov static void 1749f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1750f1220db8SAlexander V. Chernikov { 175181d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 175281d3153dSAlexander V. Chernikov uint32_t count; 1753f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1754f1220db8SAlexander V. Chernikov 1755f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 175681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1757f1220db8SAlexander V. Chernikov 1758f1220db8SAlexander V. Chernikov if (need_header) 1759f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1760f1220db8SAlexander V. Chernikov 1761f1220db8SAlexander V. Chernikov count = i->count; 1762f1220db8SAlexander V. Chernikov while (count > 0) { 176381d3153dSAlexander V. Chernikov table_show_entry(i, tent); 176481d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 176581d3153dSAlexander V. Chernikov count--; 176681d3153dSAlexander V. Chernikov } 176781d3153dSAlexander V. Chernikov } 176881d3153dSAlexander V. Chernikov 176981d3153dSAlexander V. Chernikov static void 17700cba2b28SAlexander V. Chernikov table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 17710cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip) 17720cba2b28SAlexander V. Chernikov { 17732530ed9eSAndrey V. Elsukov char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; 17742530ed9eSAndrey V. Elsukov struct sockaddr_in6 sa6; 17750cba2b28SAlexander V. Chernikov uint32_t flag, i, l; 17760cba2b28SAlexander V. Chernikov size_t sz; 17770cba2b28SAlexander V. Chernikov struct in_addr a4; 17780cba2b28SAlexander V. Chernikov 17790cba2b28SAlexander V. Chernikov sz = bufsize; 17800cba2b28SAlexander V. Chernikov 17810cba2b28SAlexander V. Chernikov /* 17820cba2b28SAlexander V. Chernikov * Some shorthands for printing values: 17830cba2b28SAlexander V. Chernikov * legacy assumes all values are equal, so keep the first one. 17840cba2b28SAlexander V. Chernikov */ 17850cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 17860cba2b28SAlexander V. Chernikov if (print_ip != 0) { 17870cba2b28SAlexander V. Chernikov flag = htonl(v->tag); 17880cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &flag, buf, sz); 17890cba2b28SAlexander V. Chernikov } else 17900cba2b28SAlexander V. Chernikov snprintf(buf, sz, "%u", v->tag); 17910cba2b28SAlexander V. Chernikov return; 17920cba2b28SAlexander V. Chernikov } 17930cba2b28SAlexander V. Chernikov 17940cba2b28SAlexander V. Chernikov for (i = 1; i < (1 << 31); i *= 2) { 17950cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 17960cba2b28SAlexander V. Chernikov continue; 17970cba2b28SAlexander V. Chernikov l = 0; 17980cba2b28SAlexander V. Chernikov 17990cba2b28SAlexander V. Chernikov switch (flag) { 18000cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 18010cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->tag); 18020cba2b28SAlexander V. Chernikov break; 18030cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 18040cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->pipe); 18050cba2b28SAlexander V. Chernikov break; 18060cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 18070cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->divert); 18080cba2b28SAlexander V. Chernikov break; 18090cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 18100cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->skipto); 18110cba2b28SAlexander V. Chernikov break; 18120cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 18130cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->netgraph); 18140cba2b28SAlexander V. Chernikov break; 18150cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 18160cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->fib); 18170cba2b28SAlexander V. Chernikov break; 18180cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 18190cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->nat); 18200cba2b28SAlexander V. Chernikov break; 18210cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 18220cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->limit); 18230cba2b28SAlexander V. Chernikov break; 18240cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 18250cba2b28SAlexander V. Chernikov a4.s_addr = htonl(v->nh4); 18260cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); 18270cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 18280cba2b28SAlexander V. Chernikov break; 18290cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 18300cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->dscp); 18310cba2b28SAlexander V. Chernikov break; 18320cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 18332530ed9eSAndrey V. Elsukov sa6.sin6_family = AF_INET6; 18342530ed9eSAndrey V. Elsukov sa6.sin6_len = sizeof(sa6); 18352530ed9eSAndrey V. Elsukov sa6.sin6_addr = v->nh6; 18362530ed9eSAndrey V. Elsukov sa6.sin6_port = 0; 18372530ed9eSAndrey V. Elsukov sa6.sin6_scope_id = v->zoneid; 18382530ed9eSAndrey V. Elsukov if (getnameinfo((const struct sockaddr *)&sa6, 18392530ed9eSAndrey V. Elsukov sa6.sin6_len, abuf, sizeof(abuf), NULL, 0, 18402530ed9eSAndrey V. Elsukov NI_NUMERICHOST) == 0) 18410cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 18420cba2b28SAlexander V. Chernikov break; 18430cba2b28SAlexander V. Chernikov } 18440cba2b28SAlexander V. Chernikov 18450cba2b28SAlexander V. Chernikov buf += l; 18460cba2b28SAlexander V. Chernikov sz -= l; 18470cba2b28SAlexander V. Chernikov } 18480cba2b28SAlexander V. Chernikov 18490cba2b28SAlexander V. Chernikov if (sz != bufsize) 18500cba2b28SAlexander V. Chernikov *(buf - 1) = '\0'; 18510cba2b28SAlexander V. Chernikov } 18520cba2b28SAlexander V. Chernikov 18530cba2b28SAlexander V. Chernikov static void 185481d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 185581d3153dSAlexander V. Chernikov { 18560cba2b28SAlexander V. Chernikov char *comma, tbuf[128], pval[128]; 1857914bffb6SAlexander V. Chernikov void *paddr; 1858914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 185981d3153dSAlexander V. Chernikov 18600cba2b28SAlexander V. Chernikov table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, 18610cba2b28SAlexander V. Chernikov co.do_value_as_ip); 1862914bffb6SAlexander V. Chernikov 1863f1220db8SAlexander V. Chernikov switch (i->type) { 1864c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1865f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 186681d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1867914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1868f1220db8SAlexander V. Chernikov break; 1869f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1870f1220db8SAlexander V. Chernikov /* Interface names */ 1871914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1872b23d5de9SAlexander V. Chernikov break; 1873b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1874b23d5de9SAlexander V. Chernikov /* numbers */ 1875914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1876b23d5de9SAlexander V. Chernikov break; 1877914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1878914bffb6SAlexander V. Chernikov /* flows */ 1879914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1880914bffb6SAlexander V. Chernikov comma = ""; 1881914bffb6SAlexander V. Chernikov 1882914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1883914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1884914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1885914bffb6SAlexander V. Chernikov else 1886914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1887914bffb6SAlexander V. Chernikov 1888914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1889914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1890914bffb6SAlexander V. Chernikov comma = ","; 1891914bffb6SAlexander V. Chernikov } 1892914bffb6SAlexander V. Chernikov 1893914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1894914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1895914bffb6SAlexander V. Chernikov comma = ","; 1896914bffb6SAlexander V. Chernikov } 1897914bffb6SAlexander V. Chernikov 1898914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1899914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1900914bffb6SAlexander V. Chernikov comma = ","; 1901914bffb6SAlexander V. Chernikov } 1902914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1903914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1904914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1905914bffb6SAlexander V. Chernikov else 1906914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1907914bffb6SAlexander V. Chernikov 1908914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1909914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1910914bffb6SAlexander V. Chernikov comma = ","; 1911914bffb6SAlexander V. Chernikov } 1912914bffb6SAlexander V. Chernikov 1913914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1914914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1915914bffb6SAlexander V. Chernikov comma = ","; 1916914bffb6SAlexander V. Chernikov } 1917914bffb6SAlexander V. Chernikov 1918914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1919f1220db8SAlexander V. Chernikov } 1920f1220db8SAlexander V. Chernikov } 1921f1220db8SAlexander V. Chernikov 19229d099b4fSAlexander V. Chernikov static int 19230cba2b28SAlexander V. Chernikov table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) 19249d099b4fSAlexander V. Chernikov { 19259d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 19269d099b4fSAlexander V. Chernikov size_t sz; 19279d099b4fSAlexander V. Chernikov 19289d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 19299d099b4fSAlexander V. Chernikov sz = sizeof(req); 19309d099b4fSAlexander V. Chernikov 1931b6462881SAlexander V. Chernikov if (do_get3(opcode, &req.opheader, &sz) != 0) 1932b6462881SAlexander V. Chernikov if (errno != ENOMEM) 1933b6462881SAlexander V. Chernikov return (errno); 19349d099b4fSAlexander V. Chernikov 19359d099b4fSAlexander V. Chernikov sz = req.size; 19369d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 19379d099b4fSAlexander V. Chernikov return (ENOMEM); 19389d099b4fSAlexander V. Chernikov 19399d099b4fSAlexander V. Chernikov olh->size = sz; 1940b6462881SAlexander V. Chernikov if (do_get3(opcode, &olh->opheader, &sz) != 0) { 19419d099b4fSAlexander V. Chernikov free(olh); 1942b6462881SAlexander V. Chernikov return (errno); 19439d099b4fSAlexander V. Chernikov } 19449d099b4fSAlexander V. Chernikov 19459d099b4fSAlexander V. Chernikov *polh = olh; 19469d099b4fSAlexander V. Chernikov return (0); 19479d099b4fSAlexander V. Chernikov } 19489d099b4fSAlexander V. Chernikov 19490cba2b28SAlexander V. Chernikov static int 19500cba2b28SAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 19510cba2b28SAlexander V. Chernikov { 19520cba2b28SAlexander V. Chernikov 19530cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); 19540cba2b28SAlexander V. Chernikov } 19550cba2b28SAlexander V. Chernikov 19560cba2b28SAlexander V. Chernikov static int 19570cba2b28SAlexander V. Chernikov table_do_get_vlist(ipfw_obj_lheader **polh) 19580cba2b28SAlexander V. Chernikov { 19590cba2b28SAlexander V. Chernikov 19600cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); 19610cba2b28SAlexander V. Chernikov } 19620cba2b28SAlexander V. Chernikov 19639d099b4fSAlexander V. Chernikov void 19649d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 19659d099b4fSAlexander V. Chernikov { 19669d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 19679d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 19689d099b4fSAlexander V. Chernikov int error, i; 19699d099b4fSAlexander V. Chernikov const char *atype; 19709d099b4fSAlexander V. Chernikov 19719d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 19729d099b4fSAlexander V. Chernikov if (error != 0) 19739d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 19749d099b4fSAlexander V. Chernikov 19759d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 19769d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 19779d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 19789d099b4fSAlexander V. Chernikov atype = "unknown"; 19798ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 19808ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 19819d099b4fSAlexander V. Chernikov 19829d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 19839d099b4fSAlexander V. Chernikov } 19849d099b4fSAlexander V. Chernikov 19859d099b4fSAlexander V. Chernikov free(olh); 19869d099b4fSAlexander V. Chernikov } 19879d099b4fSAlexander V. Chernikov 19880cba2b28SAlexander V. Chernikov 19890cba2b28SAlexander V. Chernikov /* Copy of current kernel table_value structure */ 19900cba2b28SAlexander V. Chernikov struct _table_value { 19910cba2b28SAlexander V. Chernikov uint32_t tag; /* O_TAG/O_TAGGED */ 19920cba2b28SAlexander V. Chernikov uint32_t pipe; /* O_PIPE/O_QUEUE */ 19930cba2b28SAlexander V. Chernikov uint16_t divert; /* O_DIVERT/O_TEE */ 19940cba2b28SAlexander V. Chernikov uint16_t skipto; /* skipto, CALLRET */ 19950cba2b28SAlexander V. Chernikov uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ 19960cba2b28SAlexander V. Chernikov uint32_t fib; /* O_SETFIB */ 19970cba2b28SAlexander V. Chernikov uint32_t nat; /* O_NAT */ 19980cba2b28SAlexander V. Chernikov uint32_t nh4; 19990cba2b28SAlexander V. Chernikov uint8_t dscp; 20002530ed9eSAndrey V. Elsukov uint8_t spare0; 20012530ed9eSAndrey V. Elsukov uint16_t spare1; 20020cba2b28SAlexander V. Chernikov /* -- 32 bytes -- */ 20030cba2b28SAlexander V. Chernikov struct in6_addr nh6; 20040cba2b28SAlexander V. Chernikov uint32_t limit; /* O_LIMIT */ 20052530ed9eSAndrey V. Elsukov uint32_t zoneid; 20060cba2b28SAlexander V. Chernikov uint64_t refcnt; /* Number of references */ 20070cba2b28SAlexander V. Chernikov }; 20080cba2b28SAlexander V. Chernikov 20090cba2b28SAlexander V. Chernikov int 20100cba2b28SAlexander V. Chernikov compare_values(const void *_a, const void *_b) 20110cba2b28SAlexander V. Chernikov { 20120cba2b28SAlexander V. Chernikov struct _table_value *a, *b; 20130cba2b28SAlexander V. Chernikov 20140cba2b28SAlexander V. Chernikov a = (struct _table_value *)_a; 20150cba2b28SAlexander V. Chernikov b = (struct _table_value *)_b; 20160cba2b28SAlexander V. Chernikov 20170cba2b28SAlexander V. Chernikov if (a->spare1 < b->spare1) 20180cba2b28SAlexander V. Chernikov return (-1); 20190cba2b28SAlexander V. Chernikov else if (a->spare1 > b->spare1) 20200cba2b28SAlexander V. Chernikov return (1); 20210cba2b28SAlexander V. Chernikov 20220cba2b28SAlexander V. Chernikov return (0); 20230cba2b28SAlexander V. Chernikov } 20240cba2b28SAlexander V. Chernikov 20250cba2b28SAlexander V. Chernikov void 20260cba2b28SAlexander V. Chernikov ipfw_list_values(int ac, char *av[]) 20270cba2b28SAlexander V. Chernikov { 20280cba2b28SAlexander V. Chernikov ipfw_obj_lheader *olh; 20290cba2b28SAlexander V. Chernikov struct _table_value *v; 20300cba2b28SAlexander V. Chernikov int error, i; 20310cba2b28SAlexander V. Chernikov uint32_t vmask; 20320cba2b28SAlexander V. Chernikov char buf[128]; 20330cba2b28SAlexander V. Chernikov 20340cba2b28SAlexander V. Chernikov error = table_do_get_vlist(&olh); 20350cba2b28SAlexander V. Chernikov if (error != 0) 20360cba2b28SAlexander V. Chernikov err(EX_OSERR, "Unable to request value list"); 20370cba2b28SAlexander V. Chernikov 20380cba2b28SAlexander V. Chernikov vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ 20390cba2b28SAlexander V. Chernikov 20400cba2b28SAlexander V. Chernikov table_print_valheader(buf, sizeof(buf), vmask); 20410cba2b28SAlexander V. Chernikov printf("HEADER: %s\n", buf); 20420cba2b28SAlexander V. Chernikov v = (struct _table_value *)(olh + 1); 20430cba2b28SAlexander V. Chernikov qsort(v, olh->count, olh->objsize, compare_values); 20440cba2b28SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 20450cba2b28SAlexander V. Chernikov table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, 20460cba2b28SAlexander V. Chernikov vmask, 0); 2047d3de6c1dSAlexander V. Chernikov printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf); 20480cba2b28SAlexander V. Chernikov v = (struct _table_value *)((caddr_t)v + olh->objsize); 20490cba2b28SAlexander V. Chernikov } 20500cba2b28SAlexander V. Chernikov 20510cba2b28SAlexander V. Chernikov free(olh); 20520cba2b28SAlexander V. Chernikov } 20530cba2b28SAlexander V. Chernikov 20546c2997ffSAlexander V. Chernikov int 20552acdf79fSAndrey V. Elsukov table_check_name(const char *tablename) 20566c2997ffSAlexander V. Chernikov { 20576c2997ffSAlexander V. Chernikov 20582acdf79fSAndrey V. Elsukov if (ipfw_check_object_name(tablename) != 0) 20596c2997ffSAlexander V. Chernikov return (EINVAL); 2060ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 2061ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 2062ac35ff17SAlexander V. Chernikov return (EINVAL); 20636c2997ffSAlexander V. Chernikov return (0); 20646c2997ffSAlexander V. Chernikov } 20656c2997ffSAlexander V. Chernikov 2066