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); 56*2acdf79fSAndrey V. Elsukov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, 57*2acdf79fSAndrey V. Elsukov uint32_t set, uint16_t uidx); 58f1220db8SAlexander V. Chernikov 59f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 60f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 61720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); 62f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 6381d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 64f1220db8SAlexander V. Chernikov 65ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 660cba2b28SAlexander V. Chernikov char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi); 67ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 680cba2b28SAlexander V. Chernikov char *arg, uint8_t type, uint32_t vmask); 690cba2b28SAlexander V. Chernikov static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 700cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip); 71ac35ff17SAlexander V. Chernikov 72f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 73f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 74f1220db8SAlexander V. Chernikov 75f1220db8SAlexander V. Chernikov #ifndef s6_addr32 76f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 77f1220db8SAlexander V. Chernikov #endif 78f1220db8SAlexander V. Chernikov 79ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 80c21034b7SAlexander V. Chernikov { "addr", IPFW_TABLE_ADDR }, 81ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 82b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 83914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 84ac35ff17SAlexander V. Chernikov { NULL, 0 } 85ac35ff17SAlexander V. Chernikov }; 86ac35ff17SAlexander V. Chernikov 87ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 880cba2b28SAlexander V. Chernikov { "skipto", IPFW_VTYPE_SKIPTO }, 890cba2b28SAlexander V. Chernikov { "pipe", IPFW_VTYPE_PIPE }, 900cba2b28SAlexander V. Chernikov { "fib", IPFW_VTYPE_FIB }, 910cba2b28SAlexander V. Chernikov { "nat", IPFW_VTYPE_NAT }, 920cba2b28SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 930cba2b28SAlexander V. Chernikov { "tag", IPFW_VTYPE_TAG }, 940cba2b28SAlexander V. Chernikov { "divert", IPFW_VTYPE_DIVERT }, 950cba2b28SAlexander V. Chernikov { "netgraph", IPFW_VTYPE_NETGRAPH }, 960cba2b28SAlexander V. Chernikov { "limit", IPFW_VTYPE_LIMIT }, 970cba2b28SAlexander V. Chernikov { "ipv4", IPFW_VTYPE_NH4 }, 980cba2b28SAlexander V. Chernikov { "ipv6", IPFW_VTYPE_NH6 }, 99adf3b2b9SAlexander V. Chernikov { NULL, 0 } 100adf3b2b9SAlexander V. Chernikov }; 101adf3b2b9SAlexander V. Chernikov 102ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 103ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 104ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 10546d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 106ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 107ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 108adf3b2b9SAlexander V. Chernikov { "modify", TOK_MODIFY }, 10946d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 110ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 111358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 112ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 11381d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 1143a845e10SAlexander V. Chernikov { "atomic", TOK_ATOMIC }, 1154f43138aSAlexander V. Chernikov { "lock", TOK_LOCK }, 1164f43138aSAlexander V. Chernikov { "unlock", TOK_UNLOCK }, 117ac35ff17SAlexander V. Chernikov { NULL, 0 } 118ac35ff17SAlexander V. Chernikov }; 119ac35ff17SAlexander V. Chernikov 120f1220db8SAlexander V. Chernikov static int 121f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 122f1220db8SAlexander V. Chernikov { 123f1220db8SAlexander V. Chernikov struct hostent *he; 124f1220db8SAlexander V. Chernikov 125f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 126f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 127f1220db8SAlexander V. Chernikov return(-1); 128f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 129f1220db8SAlexander V. Chernikov } 130f1220db8SAlexander V. Chernikov return(0); 131f1220db8SAlexander V. Chernikov } 132f1220db8SAlexander V. Chernikov 133f1220db8SAlexander V. Chernikov /* 134f1220db8SAlexander V. Chernikov * This one handles all table-related commands 135ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 136be695df9SAlexander V. Chernikov * ipfw table NAME modify ... 137ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 138be695df9SAlexander V. Chernikov * ipfw table NAME swap NAME 139be695df9SAlexander V. Chernikov * ipfw table NAME lock 140be695df9SAlexander V. Chernikov * ipfw table NAME unlock 141ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 142be695df9SAlexander V. Chernikov * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] .. 143be695df9SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] [addr[/masklen]] .. 144be695df9SAlexander V. Chernikov * ipfw table NAME lookup addr 145ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 146ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 147ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 148be695df9SAlexander V. Chernikov * ipfw table {NAME | all} detail 149f1220db8SAlexander V. Chernikov */ 150f1220db8SAlexander V. Chernikov void 151f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 152f1220db8SAlexander V. Chernikov { 153ac35ff17SAlexander V. Chernikov int do_add, is_all; 1543a845e10SAlexander V. Chernikov int atomic, error, tcmd; 155ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 156ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 157f1220db8SAlexander V. Chernikov char *tablename; 158ac35ff17SAlexander V. Chernikov uint32_t set; 159358b9d09SAlexander V. Chernikov void *arg; 160f1220db8SAlexander V. Chernikov 161ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 162ac35ff17SAlexander V. Chernikov is_all = 0; 163ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 164ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 165ac35ff17SAlexander V. Chernikov else 166ac35ff17SAlexander V. Chernikov set = 0; 167f1220db8SAlexander V. Chernikov 168f1220db8SAlexander V. Chernikov ac--; av++; 1699d099b4fSAlexander V. Chernikov NEED1("table needs name"); 170f1220db8SAlexander V. Chernikov tablename = *av; 171f1220db8SAlexander V. Chernikov 172ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 173ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 174ac35ff17SAlexander V. Chernikov oh.idx = 1; 175ac35ff17SAlexander V. Chernikov } else { 176ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 177ac35ff17SAlexander V. Chernikov is_all = 1; 178ac35ff17SAlexander V. Chernikov else 179ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 180ac35ff17SAlexander V. Chernikov } 181ac35ff17SAlexander V. Chernikov ac--; av++; 1829d099b4fSAlexander V. Chernikov NEED1("table needs command"); 183ac35ff17SAlexander V. Chernikov 184be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 1853a845e10SAlexander V. Chernikov /* Check if atomic operation was requested */ 1863a845e10SAlexander V. Chernikov atomic = 0; 1873a845e10SAlexander V. Chernikov if (tcmd == TOK_ATOMIC) { 1883a845e10SAlexander V. Chernikov ac--; av++; 1893a845e10SAlexander V. Chernikov NEED1("atomic needs command"); 190be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 1913a845e10SAlexander V. Chernikov switch (tcmd) { 1923a845e10SAlexander V. Chernikov case TOK_ADD: 1933a845e10SAlexander V. Chernikov break; 1943a845e10SAlexander V. Chernikov default: 1953a845e10SAlexander V. Chernikov errx(EX_USAGE, "atomic is not compatible with %s", *av); 1963a845e10SAlexander V. Chernikov } 1973a845e10SAlexander V. Chernikov atomic = 1; 1983a845e10SAlexander V. Chernikov } 199ac35ff17SAlexander V. Chernikov 200ac35ff17SAlexander V. Chernikov switch (tcmd) { 201ac35ff17SAlexander V. Chernikov case TOK_LIST: 202ac35ff17SAlexander V. Chernikov case TOK_INFO: 203358b9d09SAlexander V. Chernikov case TOK_DETAIL: 204ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 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: 228ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 229ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 230ac35ff17SAlexander V. Chernikov break; 231ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 232f1220db8SAlexander V. Chernikov if (is_all == 0) { 233ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 234f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 235f1220db8SAlexander V. Chernikov tablename); 236f1220db8SAlexander V. Chernikov } else { 237ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 238f1220db8SAlexander V. Chernikov if (error != 0) 239f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 240f1220db8SAlexander V. Chernikov } 241ac35ff17SAlexander V. Chernikov break; 24246d52008SAlexander V. Chernikov case TOK_SWAP: 24346d52008SAlexander V. Chernikov ac--; av++; 24446d52008SAlexander V. Chernikov NEED1("second table name required"); 24546d52008SAlexander V. Chernikov table_swap(&oh, *av); 24646d52008SAlexander V. Chernikov break; 2474f43138aSAlexander V. Chernikov case TOK_LOCK: 2484f43138aSAlexander V. Chernikov case TOK_UNLOCK: 2494f43138aSAlexander V. Chernikov table_lock(&oh, (tcmd == TOK_LOCK)); 2504f43138aSAlexander V. Chernikov break; 251358b9d09SAlexander V. Chernikov case TOK_DETAIL: 252ac35ff17SAlexander V. Chernikov case TOK_INFO: 253358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 254f1220db8SAlexander V. Chernikov if (is_all == 0) { 255ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 256f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 257358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 258f1220db8SAlexander V. Chernikov } else { 259358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 260f1220db8SAlexander V. Chernikov if (error != 0) 261f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 262f1220db8SAlexander V. Chernikov } 263ac35ff17SAlexander V. Chernikov break; 264ac35ff17SAlexander V. Chernikov case TOK_LIST: 265ac35ff17SAlexander V. Chernikov if (is_all == 0) { 266ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 267ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 268ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 269ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 270f1220db8SAlexander V. Chernikov } else { 271ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 272ac35ff17SAlexander V. Chernikov if (error != 0) 273ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 274f1220db8SAlexander V. Chernikov } 275ac35ff17SAlexander V. Chernikov break; 27681d3153dSAlexander V. Chernikov case TOK_LOOKUP: 27781d3153dSAlexander V. Chernikov ac--; av++; 27881d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 27981d3153dSAlexander V. Chernikov break; 280f1220db8SAlexander V. Chernikov } 281f1220db8SAlexander V. Chernikov } 282f1220db8SAlexander V. Chernikov 283f1220db8SAlexander V. Chernikov static void 284*2acdf79fSAndrey V. Elsukov table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint32_t set, 285*2acdf79fSAndrey V. Elsukov uint16_t uidx) 286f1220db8SAlexander V. Chernikov { 287f1220db8SAlexander V. Chernikov 288563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 289f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 290f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 291ac35ff17SAlexander V. Chernikov ntlv->set = set; 292f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 293f1220db8SAlexander V. Chernikov } 294f1220db8SAlexander V. Chernikov 295f1220db8SAlexander V. Chernikov static void 296f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 297f1220db8SAlexander V. Chernikov { 298f1220db8SAlexander V. Chernikov 299f1220db8SAlexander V. Chernikov oh->idx = 1; 30081d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 301ac35ff17SAlexander V. Chernikov } 302ac35ff17SAlexander V. Chernikov 303ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 304ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 305ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 306ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 3074c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 3084f43138aSAlexander V. Chernikov { "locked", TOK_LOCK }, 309ac35ff17SAlexander V. Chernikov { NULL, 0 } 310ac35ff17SAlexander V. Chernikov }; 311ac35ff17SAlexander V. Chernikov 312914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 313914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 314914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 315914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 316914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 317914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 318914bffb6SAlexander V. Chernikov { NULL, 0 } 319914bffb6SAlexander V. Chernikov }; 320914bffb6SAlexander V. Chernikov 321914bffb6SAlexander V. Chernikov int 322914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 323914bffb6SAlexander V. Chernikov { 3240cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 3250cba2b28SAlexander V. Chernikov char *e; 326914bffb6SAlexander V. Chernikov 327914bffb6SAlexander V. Chernikov /* Parse type options */ 328914bffb6SAlexander V. Chernikov switch(ttype) { 329914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 330914bffb6SAlexander V. Chernikov fset = fclear = 0; 3310cba2b28SAlexander V. Chernikov if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0) 3320cba2b28SAlexander V. Chernikov errx(EX_USAGE, 3330cba2b28SAlexander V. Chernikov "unable to parse flow option %s", e); 334914bffb6SAlexander V. Chernikov *tflags = fset; 335914bffb6SAlexander V. Chernikov break; 336914bffb6SAlexander V. Chernikov default: 337914bffb6SAlexander V. Chernikov return (EX_USAGE); 338914bffb6SAlexander V. Chernikov } 339914bffb6SAlexander V. Chernikov 340914bffb6SAlexander V. Chernikov return (0); 341914bffb6SAlexander V. Chernikov } 342914bffb6SAlexander V. Chernikov 343914bffb6SAlexander V. Chernikov void 344914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 345914bffb6SAlexander V. Chernikov { 346914bffb6SAlexander V. Chernikov const char *tname; 347914bffb6SAlexander V. Chernikov int l; 348914bffb6SAlexander V. Chernikov 349914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 350914bffb6SAlexander V. Chernikov tname = "unknown"; 351914bffb6SAlexander V. Chernikov 352914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 353914bffb6SAlexander V. Chernikov tbuf += l; 354914bffb6SAlexander V. Chernikov size -= l; 355914bffb6SAlexander V. Chernikov 356914bffb6SAlexander V. Chernikov switch(type) { 357914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 358914bffb6SAlexander V. Chernikov if (tflags != 0) { 359914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 360914bffb6SAlexander V. Chernikov l--; 361914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 362914bffb6SAlexander V. Chernikov } 363914bffb6SAlexander V. Chernikov break; 364914bffb6SAlexander V. Chernikov } 365914bffb6SAlexander V. Chernikov } 366914bffb6SAlexander V. Chernikov 367ac35ff17SAlexander V. Chernikov /* 368ac35ff17SAlexander V. Chernikov * Creates new table 369ac35ff17SAlexander V. Chernikov * 370c21034b7SAlexander V. Chernikov * ipfw table NAME create [ type { addr | iface | number | flow } ] 371ac35ff17SAlexander V. Chernikov * [ algo algoname ] 372ac35ff17SAlexander V. Chernikov */ 373ac35ff17SAlexander V. Chernikov static void 374ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 375ac35ff17SAlexander V. Chernikov { 376ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 377ac35ff17SAlexander V. Chernikov int error, tcmd, val; 3780cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 3790cba2b28SAlexander V. Chernikov char *e, *p; 380ac35ff17SAlexander V. Chernikov char tbuf[128]; 381ac35ff17SAlexander V. Chernikov 382ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 383ac35ff17SAlexander V. Chernikov 384ac35ff17SAlexander V. Chernikov while (ac > 0) { 385be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 386ac35ff17SAlexander V. Chernikov ac--; av++; 387ac35ff17SAlexander V. Chernikov 388ac35ff17SAlexander V. Chernikov switch (tcmd) { 3894c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 3904c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 3914c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 3924c0c07a5SAlexander V. Chernikov ac--; av++; 3934c0c07a5SAlexander V. Chernikov break; 394ac35ff17SAlexander V. Chernikov case TOK_TYPE: 395ac35ff17SAlexander V. Chernikov NEED1("table type required"); 396914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 397914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 398914bffb6SAlexander V. Chernikov *p++ = '\0'; 399ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 400914bffb6SAlexander V. Chernikov if (val == -1) { 401914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 402914bffb6SAlexander V. Chernikov ", "); 403914bffb6SAlexander V. Chernikov errx(EX_USAGE, 404914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 405ac35ff17SAlexander V. Chernikov *av, tbuf); 406914bffb6SAlexander V. Chernikov } 407914bffb6SAlexander V. Chernikov xi.type = val; 408914bffb6SAlexander V. Chernikov if (p != NULL) { 409914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 410914bffb6SAlexander V. Chernikov if (error != 0) 411914bffb6SAlexander V. Chernikov errx(EX_USAGE, 412914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 413914bffb6SAlexander V. Chernikov } 414914bffb6SAlexander V. Chernikov ac--; av++; 415ac35ff17SAlexander V. Chernikov break; 416ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 417ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 4180cba2b28SAlexander V. Chernikov fset = fclear = 0; 4190cba2b28SAlexander V. Chernikov val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear); 420ac35ff17SAlexander V. Chernikov if (val != -1) { 4210cba2b28SAlexander V. Chernikov xi.vmask = fset; 422ac35ff17SAlexander V. Chernikov ac--; av++; 423ac35ff17SAlexander V. Chernikov break; 424ac35ff17SAlexander V. Chernikov } 425ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 426ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 4270cba2b28SAlexander V. Chernikov e, tbuf); 428adf3b2b9SAlexander V. Chernikov break; 429ac35ff17SAlexander V. Chernikov case TOK_ALGO: 430ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 431ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 432ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 433ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 434ac35ff17SAlexander V. Chernikov ac--; av++; 435ac35ff17SAlexander V. Chernikov break; 4364f43138aSAlexander V. Chernikov case TOK_LOCK: 4374f43138aSAlexander V. Chernikov xi.flags |= IPFW_TGFLAGS_LOCKED; 4384f43138aSAlexander V. Chernikov break; 439ac35ff17SAlexander V. Chernikov } 440ac35ff17SAlexander V. Chernikov } 441ac35ff17SAlexander V. Chernikov 442463a577bSEitan Adler /* Set some defaults to preserve compatibility. */ 443fd0869d5SAlexander V. Chernikov if (xi.algoname[0] == '\0' && xi.type == 0) 444c21034b7SAlexander V. Chernikov xi.type = IPFW_TABLE_ADDR; 4450cba2b28SAlexander V. Chernikov if (xi.vmask == 0) 4460cba2b28SAlexander V. Chernikov xi.vmask = IPFW_VTYPE_LEGACY; 447fd0869d5SAlexander V. Chernikov 448ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 449ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 450f1220db8SAlexander V. Chernikov } 451f1220db8SAlexander V. Chernikov 452f1220db8SAlexander V. Chernikov /* 453ac35ff17SAlexander V. Chernikov * Creates new table 454ac35ff17SAlexander V. Chernikov * 455ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 456ac35ff17SAlexander V. Chernikov * 457f1220db8SAlexander V. Chernikov * Returns 0 on success. 458f1220db8SAlexander V. Chernikov */ 459f1220db8SAlexander V. Chernikov static int 460ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 461f1220db8SAlexander V. Chernikov { 462ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 463ac35ff17SAlexander V. Chernikov int error; 464f1220db8SAlexander V. Chernikov 465ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 466ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 467ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 468ac35ff17SAlexander V. Chernikov 469ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 470ac35ff17SAlexander V. Chernikov 471ac35ff17SAlexander V. Chernikov return (error); 472ac35ff17SAlexander V. Chernikov } 473ac35ff17SAlexander V. Chernikov 474ac35ff17SAlexander V. Chernikov /* 475adf3b2b9SAlexander V. Chernikov * Modifies existing table 476adf3b2b9SAlexander V. Chernikov * 4770cba2b28SAlexander V. Chernikov * ipfw table NAME modify [ limit number ] 478adf3b2b9SAlexander V. Chernikov */ 479adf3b2b9SAlexander V. Chernikov static void 480adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[]) 481adf3b2b9SAlexander V. Chernikov { 482adf3b2b9SAlexander V. Chernikov ipfw_xtable_info xi; 483b6462881SAlexander V. Chernikov int tcmd; 484adf3b2b9SAlexander V. Chernikov 485adf3b2b9SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 486adf3b2b9SAlexander V. Chernikov 487adf3b2b9SAlexander V. Chernikov while (ac > 0) { 488be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 489adf3b2b9SAlexander V. Chernikov ac--; av++; 490adf3b2b9SAlexander V. Chernikov 491adf3b2b9SAlexander V. Chernikov switch (tcmd) { 492adf3b2b9SAlexander V. Chernikov case TOK_LIMIT: 493adf3b2b9SAlexander V. Chernikov NEED1("limit value required"); 494adf3b2b9SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 495adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LIMIT; 496adf3b2b9SAlexander V. Chernikov ac--; av++; 497adf3b2b9SAlexander V. Chernikov break; 4980cba2b28SAlexander V. Chernikov default: 4990cba2b28SAlexander V. Chernikov errx(EX_USAGE, "cmd is not supported for modificatiob"); 500adf3b2b9SAlexander V. Chernikov } 501adf3b2b9SAlexander V. Chernikov } 502adf3b2b9SAlexander V. Chernikov 503b6462881SAlexander V. Chernikov if (table_do_modify(oh, &xi) != 0) 504adf3b2b9SAlexander V. Chernikov err(EX_OSERR, "Table modification failed"); 505adf3b2b9SAlexander V. Chernikov } 506adf3b2b9SAlexander V. Chernikov 507adf3b2b9SAlexander V. Chernikov /* 508adf3b2b9SAlexander V. Chernikov * Modifies existing table. 509adf3b2b9SAlexander V. Chernikov * 510adf3b2b9SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 511adf3b2b9SAlexander V. Chernikov * 512adf3b2b9SAlexander V. Chernikov * Returns 0 on success. 513adf3b2b9SAlexander V. Chernikov */ 514adf3b2b9SAlexander V. Chernikov static int 515adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 516adf3b2b9SAlexander V. Chernikov { 517adf3b2b9SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 518adf3b2b9SAlexander V. Chernikov int error; 519adf3b2b9SAlexander V. Chernikov 520adf3b2b9SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 521adf3b2b9SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 522adf3b2b9SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 523adf3b2b9SAlexander V. Chernikov 524adf3b2b9SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 525adf3b2b9SAlexander V. Chernikov 526adf3b2b9SAlexander V. Chernikov return (error); 527adf3b2b9SAlexander V. Chernikov } 5284f43138aSAlexander V. Chernikov 5294f43138aSAlexander V. Chernikov /* 5304f43138aSAlexander V. Chernikov * Locks or unlocks given table 5314f43138aSAlexander V. Chernikov */ 5324f43138aSAlexander V. Chernikov static void 5334f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock) 5344f43138aSAlexander V. Chernikov { 5354f43138aSAlexander V. Chernikov ipfw_xtable_info xi; 5364f43138aSAlexander V. Chernikov 5374f43138aSAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 5384f43138aSAlexander V. Chernikov 5394f43138aSAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LOCK; 5404f43138aSAlexander V. Chernikov xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; 5414f43138aSAlexander V. Chernikov 542b6462881SAlexander V. Chernikov if (table_do_modify(oh, &xi) != 0) 5434f43138aSAlexander V. Chernikov err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); 5444f43138aSAlexander V. Chernikov } 5454f43138aSAlexander V. Chernikov 546adf3b2b9SAlexander V. Chernikov /* 547ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 548ac35ff17SAlexander V. Chernikov * Returns 0 on success. 549ac35ff17SAlexander V. Chernikov */ 550ac35ff17SAlexander V. Chernikov static int 551ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 552ac35ff17SAlexander V. Chernikov { 553ac35ff17SAlexander V. Chernikov 554ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 555f1220db8SAlexander V. Chernikov return (-1); 556f1220db8SAlexander V. Chernikov 557f1220db8SAlexander V. Chernikov return (0); 558f1220db8SAlexander V. Chernikov } 559f1220db8SAlexander V. Chernikov 560f1220db8SAlexander V. Chernikov /* 561ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 562f1220db8SAlexander V. Chernikov * Returns 0 on success. 563f1220db8SAlexander V. Chernikov */ 564f1220db8SAlexander V. Chernikov static int 565ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 566f1220db8SAlexander V. Chernikov { 567f1220db8SAlexander V. Chernikov 568ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 569f1220db8SAlexander V. Chernikov return (-1); 570f1220db8SAlexander V. Chernikov 571f1220db8SAlexander V. Chernikov return (0); 572f1220db8SAlexander V. Chernikov } 573f1220db8SAlexander V. Chernikov 57446d52008SAlexander V. Chernikov static int 57546d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 57646d52008SAlexander V. Chernikov { 57746d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 57846d52008SAlexander V. Chernikov int error; 57946d52008SAlexander V. Chernikov 58046d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 58146d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 58246d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 58346d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 58446d52008SAlexander V. Chernikov 58546d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 58646d52008SAlexander V. Chernikov 58746d52008SAlexander V. Chernikov return (error); 58846d52008SAlexander V. Chernikov } 58946d52008SAlexander V. Chernikov 59046d52008SAlexander V. Chernikov /* 59146d52008SAlexander V. Chernikov * Swaps given table with @second one. 59246d52008SAlexander V. Chernikov */ 59346d52008SAlexander V. Chernikov static int 59446d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 59546d52008SAlexander V. Chernikov { 59646d52008SAlexander V. Chernikov int error; 59746d52008SAlexander V. Chernikov 59846d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 59946d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 60046d52008SAlexander V. Chernikov 60146d52008SAlexander V. Chernikov error = table_do_swap(oh, second); 60246d52008SAlexander V. Chernikov 60346d52008SAlexander V. Chernikov switch (error) { 60446d52008SAlexander V. Chernikov case EINVAL: 60546d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 60646d52008SAlexander V. Chernikov case EFBIG: 60746d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 60846d52008SAlexander V. Chernikov } 60946d52008SAlexander V. Chernikov 61046d52008SAlexander V. Chernikov return (0); 61146d52008SAlexander V. Chernikov } 61246d52008SAlexander V. Chernikov 61346d52008SAlexander V. Chernikov 614f1220db8SAlexander V. Chernikov /* 615ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 616f1220db8SAlexander V. Chernikov * it inside @i. 617f1220db8SAlexander V. Chernikov * Returns 0 on success. 618f1220db8SAlexander V. Chernikov */ 619f1220db8SAlexander V. Chernikov static int 620ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 621f1220db8SAlexander V. Chernikov { 622f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 623f1220db8SAlexander V. Chernikov size_t sz; 624f1220db8SAlexander V. Chernikov 625f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 626f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 627ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 628f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 629f1220db8SAlexander V. Chernikov 630b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0) 631b6462881SAlexander V. Chernikov return (errno); 632f1220db8SAlexander V. Chernikov 633f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 634ac35ff17SAlexander V. Chernikov return (EINVAL); 635f1220db8SAlexander V. Chernikov 636f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 637f1220db8SAlexander V. Chernikov 638f1220db8SAlexander V. Chernikov return (0); 639f1220db8SAlexander V. Chernikov } 640f1220db8SAlexander V. Chernikov 6415f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 6425f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 6435f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 6445f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 6455f379342SAlexander V. Chernikov { NULL, 0 } 6465f379342SAlexander V. Chernikov }; 6475f379342SAlexander V. Chernikov 6485f379342SAlexander V. Chernikov struct ta_cldata { 6495f379342SAlexander V. Chernikov uint8_t taclass; 6505f379342SAlexander V. Chernikov uint8_t spare4; 6515f379342SAlexander V. Chernikov uint16_t itemsize; 6525f379342SAlexander V. Chernikov uint16_t itemsize6; 6535f379342SAlexander V. Chernikov uint32_t size; 6545f379342SAlexander V. Chernikov uint32_t count; 6555f379342SAlexander V. Chernikov }; 6565f379342SAlexander V. Chernikov 6575f379342SAlexander V. Chernikov /* 6585f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 6595f379342SAlexander V. Chernikov */ 6605f379342SAlexander V. Chernikov static void 6615f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 6625f379342SAlexander V. Chernikov const char *af, const char *taclass) 6635f379342SAlexander V. Chernikov { 6645f379342SAlexander V. Chernikov 6655f379342SAlexander V. Chernikov switch (d->taclass) { 6665f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 6675f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 6685f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 6695f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 6705f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 6715f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 6725f379342SAlexander V. Chernikov else 6735f379342SAlexander V. Chernikov printf(" size: %u items: %u " 6745f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 6755f379342SAlexander V. Chernikov d->size, d->count, 6765f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 6775f379342SAlexander V. Chernikov break; 6785f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 6795f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 6805f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 6815f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 6825f379342SAlexander V. Chernikov d->count, d->itemsize); 6835f379342SAlexander V. Chernikov else 6845f379342SAlexander V. Chernikov printf(" items: %u " 6855f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 6865f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 6875f379342SAlexander V. Chernikov break; 6885f379342SAlexander V. Chernikov default: 6895f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 6905f379342SAlexander V. Chernikov } 6915f379342SAlexander V. Chernikov } 6925f379342SAlexander V. Chernikov 6930cba2b28SAlexander V. Chernikov static void 6940cba2b28SAlexander V. Chernikov table_print_valheader(char *buf, size_t bufsize, uint32_t vmask) 6950cba2b28SAlexander V. Chernikov { 6960cba2b28SAlexander V. Chernikov 6970cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 6980cba2b28SAlexander V. Chernikov snprintf(buf, bufsize, "legacy"); 6990cba2b28SAlexander V. Chernikov return; 7000cba2b28SAlexander V. Chernikov } 7010cba2b28SAlexander V. Chernikov 7028a6dbb64SAlexander V. Chernikov memset(buf, 0, bufsize); 7030cba2b28SAlexander V. Chernikov print_flags_buffer(buf, bufsize, tablevaltypes, vmask); 7040cba2b28SAlexander V. Chernikov } 7050cba2b28SAlexander V. Chernikov 706f1220db8SAlexander V. Chernikov /* 707f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 708f1220db8SAlexander V. Chernikov */ 709f1220db8SAlexander V. Chernikov static int 710f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 711f1220db8SAlexander V. Chernikov { 7120cba2b28SAlexander V. Chernikov const char *vtype; 7135f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 7145f379342SAlexander V. Chernikov int afdata, afitem; 7155f379342SAlexander V. Chernikov struct ta_cldata d; 716adf3b2b9SAlexander V. Chernikov char ttype[64], tvtype[64]; 717f1220db8SAlexander V. Chernikov 718914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 7190cba2b28SAlexander V. Chernikov table_print_valheader(tvtype, sizeof(tvtype), i->vmask); 720ac35ff17SAlexander V. Chernikov 721914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 7224f43138aSAlexander V. Chernikov if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) 7234f43138aSAlexander V. Chernikov printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); 7244f43138aSAlexander V. Chernikov else 725914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 7260cba2b28SAlexander V. Chernikov printf(" references: %u, valtype: %s\n", i->refcnt, tvtype); 7279d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 728f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 7294c0c07a5SAlexander V. Chernikov if (i->limit > 0) 7304c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 731f1220db8SAlexander V. Chernikov 732358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 733358b9d09SAlexander V. Chernikov if (arg == NULL) 734358b9d09SAlexander V. Chernikov return (0); 735358b9d09SAlexander V. Chernikov 7365f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 7375f379342SAlexander V. Chernikov return (0); 7385f379342SAlexander V. Chernikov tainfo = &i->ta_info; 7395f379342SAlexander V. Chernikov 7405f379342SAlexander V. Chernikov afdata = 0; 7415f379342SAlexander V. Chernikov afitem = 0; 7425f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 7435f379342SAlexander V. Chernikov afdata = 1; 7445f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 7455f379342SAlexander V. Chernikov afitem = 1; 7465f379342SAlexander V. Chernikov 7475f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7485f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 7495f379342SAlexander V. Chernikov d.size = tainfo->size4; 7505f379342SAlexander V. Chernikov d.count = tainfo->count4; 7515f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 7525f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 7535f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 7545f379342SAlexander V. Chernikov else 7555f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7565f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7575f379342SAlexander V. Chernikov vtype = "unknown"; 7585f379342SAlexander V. Chernikov 7595f379342SAlexander V. Chernikov if (afdata == 0) { 7605f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 7615f379342SAlexander V. Chernikov } else { 7625f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 7635f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7645f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 7655f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7665f379342SAlexander V. Chernikov vtype = "unknown"; 7675f379342SAlexander V. Chernikov d.size = tainfo->size6; 7685f379342SAlexander V. Chernikov d.count = tainfo->count6; 7695f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 7705f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7715f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 7725f379342SAlexander V. Chernikov } 7735f379342SAlexander V. Chernikov 774f1220db8SAlexander V. Chernikov return (0); 775f1220db8SAlexander V. Chernikov } 776f1220db8SAlexander V. Chernikov 777f1220db8SAlexander V. Chernikov 778f1220db8SAlexander V. Chernikov /* 779f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 780f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 781f1220db8SAlexander V. Chernikov */ 782f1220db8SAlexander V. Chernikov 783f1220db8SAlexander V. Chernikov static int 784f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 785f1220db8SAlexander V. Chernikov { 786f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 78781d3153dSAlexander V. Chernikov int error; 788f1220db8SAlexander V. Chernikov 789720ee730SAlexander V. Chernikov if ((error = table_do_get_list(i, &oh)) != 0) { 79081d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 79181d3153dSAlexander V. Chernikov return (error); 79281d3153dSAlexander V. Chernikov } 79381d3153dSAlexander V. Chernikov 794f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 795f1220db8SAlexander V. Chernikov 796f1220db8SAlexander V. Chernikov free(oh); 797f1220db8SAlexander V. Chernikov return (0); 798f1220db8SAlexander V. Chernikov } 799f1220db8SAlexander V. Chernikov 800f1220db8SAlexander V. Chernikov static int 801f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 802f1220db8SAlexander V. Chernikov { 803ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 804f1220db8SAlexander V. Chernikov 805ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 806ac35ff17SAlexander V. Chernikov 807ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 808ac35ff17SAlexander V. Chernikov 809ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 810f1220db8SAlexander V. Chernikov } 811f1220db8SAlexander V. Chernikov 812ac35ff17SAlexander V. Chernikov static int 813ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 8143a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent, int count, int atomic) 815ac35ff17SAlexander V. Chernikov { 816db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 8173a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent_base; 8183a845e10SAlexander V. Chernikov caddr_t pbuf; 819db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 8203a845e10SAlexander V. Chernikov int error, i; 8213a845e10SAlexander V. Chernikov size_t sz; 822ac35ff17SAlexander V. Chernikov 8233a845e10SAlexander V. Chernikov sz = sizeof(*ctlv) + sizeof(*tent) * count; 8243a845e10SAlexander V. Chernikov if (count == 1) { 825ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 8263a845e10SAlexander V. Chernikov pbuf = xbuf; 8273a845e10SAlexander V. Chernikov } else { 8283a845e10SAlexander V. Chernikov if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) 8293a845e10SAlexander V. Chernikov return (ENOMEM); 8303a845e10SAlexander V. Chernikov } 8313a845e10SAlexander V. Chernikov 8323a845e10SAlexander V. Chernikov memcpy(pbuf, oh, sizeof(*oh)); 8333a845e10SAlexander V. Chernikov oh = (ipfw_obj_header *)pbuf; 834ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 835ac35ff17SAlexander V. Chernikov 836db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 8373a845e10SAlexander V. Chernikov ctlv->count = count; 8383a845e10SAlexander V. Chernikov ctlv->head.length = sz; 8393a845e10SAlexander V. Chernikov if (atomic != 0) 8403a845e10SAlexander V. Chernikov ctlv->flags |= IPFW_CTF_ATOMIC; 841db785d31SAlexander V. Chernikov 8423a845e10SAlexander V. Chernikov tent_base = tent; 8433a845e10SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent) * count); 844db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 8453a845e10SAlexander V. Chernikov for (i = 0; i < count; i++, tent++) { 846ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 8473a845e10SAlexander V. Chernikov tent->idx = oh->idx; 8483a845e10SAlexander V. Chernikov } 849ac35ff17SAlexander V. Chernikov 8503a845e10SAlexander V. Chernikov sz += sizeof(*oh); 8513a845e10SAlexander V. Chernikov error = do_get3(cmd, &oh->opheader, &sz); 8523a845e10SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 8533a845e10SAlexander V. Chernikov /* Copy result back to provided buffer */ 8543a845e10SAlexander V. Chernikov memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); 8553a845e10SAlexander V. Chernikov 8563a845e10SAlexander V. Chernikov if (pbuf != xbuf) 8573a845e10SAlexander V. Chernikov free(pbuf); 858ac35ff17SAlexander V. Chernikov 859ac35ff17SAlexander V. Chernikov return (error); 860ac35ff17SAlexander V. Chernikov } 861ac35ff17SAlexander V. Chernikov 862ac35ff17SAlexander V. Chernikov static void 8633a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, 8643a845e10SAlexander V. Chernikov int quiet, int update, int atomic) 865ac35ff17SAlexander V. Chernikov { 8663a845e10SAlexander V. Chernikov ipfw_obj_tentry *ptent, tent, *tent_buf; 86781d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 8680cba2b28SAlexander V. Chernikov uint8_t type; 8690cba2b28SAlexander V. Chernikov uint32_t vmask; 8703a845e10SAlexander V. Chernikov int cmd, count, error, i, ignored; 8713a845e10SAlexander V. Chernikov char *texterr, *etxt, *px; 872ac35ff17SAlexander V. Chernikov 873ac35ff17SAlexander V. Chernikov if (ac == 0) 874ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 875ac35ff17SAlexander V. Chernikov 876ac35ff17SAlexander V. Chernikov if (add != 0) { 877ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 8784c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 879ac35ff17SAlexander V. Chernikov } else { 880ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 8814c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 882ac35ff17SAlexander V. Chernikov } 883ac35ff17SAlexander V. Chernikov 8843a845e10SAlexander V. Chernikov /* 8853a845e10SAlexander V. Chernikov * Calculate number of entries: 8863a845e10SAlexander V. Chernikov * Assume [key val] x N for add 8873a845e10SAlexander V. Chernikov * and 8883a845e10SAlexander V. Chernikov * key x N for delete 8893a845e10SAlexander V. Chernikov */ 8903a845e10SAlexander V. Chernikov count = (add != 0) ? ac / 2 + 1 : ac; 8913a845e10SAlexander V. Chernikov 8923a845e10SAlexander V. Chernikov if (count <= 1) { 8933a845e10SAlexander V. Chernikov /* Adding single entry with/without value */ 8943a845e10SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 8953a845e10SAlexander V. Chernikov tent_buf = &tent; 8963a845e10SAlexander V. Chernikov } else { 8973a845e10SAlexander V. Chernikov 8983a845e10SAlexander V. Chernikov if ((tent_buf = calloc(count, sizeof(tent))) == NULL) 8993a845e10SAlexander V. Chernikov errx(EX_OSERR, 9003a845e10SAlexander V. Chernikov "Unable to allocate memory for all entries"); 9013a845e10SAlexander V. Chernikov } 9023a845e10SAlexander V. Chernikov ptent = tent_buf; 9033a845e10SAlexander V. Chernikov 9043a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 9053a845e10SAlexander V. Chernikov count = 0; 9063a845e10SAlexander V. Chernikov while (ac > 0) { 9070cba2b28SAlexander V. Chernikov tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi); 9083a845e10SAlexander V. Chernikov 9093a845e10SAlexander V. Chernikov /* 910463a577bSEitan Adler * Compatibility layer: auto-create table if not exists. 9113a845e10SAlexander V. Chernikov */ 9123a845e10SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 9133a845e10SAlexander V. Chernikov xi.type = type; 9140cba2b28SAlexander V. Chernikov xi.vmask = vmask; 9153a845e10SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, 9163a845e10SAlexander V. Chernikov sizeof(xi.tablename)); 917f5846f16SMark Felder fprintf(stderr, "DEPRECATED: inserting data into " 9183a845e10SAlexander V. Chernikov "non-existent table %s. (auto-created)\n", 9193a845e10SAlexander V. Chernikov xi.tablename); 9203a845e10SAlexander V. Chernikov table_do_create(oh, &xi); 9213a845e10SAlexander V. Chernikov } 9223a845e10SAlexander V. Chernikov 9233a845e10SAlexander V. Chernikov oh->ntlv.type = type; 9243a845e10SAlexander V. Chernikov ac--; av++; 9253a845e10SAlexander V. Chernikov 9263a845e10SAlexander V. Chernikov if (add != 0 && ac > 0) { 9270cba2b28SAlexander V. Chernikov tentry_fill_value(oh, ptent, *av, type, vmask); 9283a845e10SAlexander V. Chernikov ac--; av++; 9293a845e10SAlexander V. Chernikov } 9303a845e10SAlexander V. Chernikov 9313a845e10SAlexander V. Chernikov if (update != 0) 9323a845e10SAlexander V. Chernikov ptent->head.flags |= IPFW_TF_UPDATE; 9333a845e10SAlexander V. Chernikov 9343a845e10SAlexander V. Chernikov count++; 9353a845e10SAlexander V. Chernikov ptent++; 9363a845e10SAlexander V. Chernikov } 9373a845e10SAlexander V. Chernikov 9383a845e10SAlexander V. Chernikov error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 9393a845e10SAlexander V. Chernikov 9400cba2b28SAlexander V. Chernikov quiet = 0; 9410cba2b28SAlexander V. Chernikov 9423a845e10SAlexander V. Chernikov /* 9433a845e10SAlexander V. Chernikov * Compatibility stuff: do not yell on duplicate keys or 9443a845e10SAlexander V. Chernikov * failed deletions. 9453a845e10SAlexander V. Chernikov */ 9463a845e10SAlexander V. Chernikov if (error == 0 || (error == EEXIST && add != 0) || 9473a845e10SAlexander V. Chernikov (error == ENOENT && add == 0)) { 9483a845e10SAlexander V. Chernikov if (quiet != 0) { 9493a845e10SAlexander V. Chernikov if (tent_buf != &tent) 9503a845e10SAlexander V. Chernikov free(tent_buf); 9513a845e10SAlexander V. Chernikov return; 9523a845e10SAlexander V. Chernikov } 9533a845e10SAlexander V. Chernikov } 9543a845e10SAlexander V. Chernikov 9553a845e10SAlexander V. Chernikov /* Report results back */ 9563a845e10SAlexander V. Chernikov ptent = tent_buf; 9573a845e10SAlexander V. Chernikov for (i = 0; i < count; ptent++, i++) { 9583a845e10SAlexander V. Chernikov ignored = 0; 9593a845e10SAlexander V. Chernikov switch (ptent->result) { 9603a845e10SAlexander V. Chernikov case IPFW_TR_ADDED: 9613a845e10SAlexander V. Chernikov px = "added"; 9623a845e10SAlexander V. Chernikov break; 9633a845e10SAlexander V. Chernikov case IPFW_TR_DELETED: 9643a845e10SAlexander V. Chernikov px = "deleted"; 9653a845e10SAlexander V. Chernikov break; 9663a845e10SAlexander V. Chernikov case IPFW_TR_UPDATED: 9673a845e10SAlexander V. Chernikov px = "updated"; 9683a845e10SAlexander V. Chernikov break; 9693a845e10SAlexander V. Chernikov case IPFW_TR_LIMIT: 9703a845e10SAlexander V. Chernikov px = "limit"; 9713a845e10SAlexander V. Chernikov ignored = 1; 9723a845e10SAlexander V. Chernikov break; 9733a845e10SAlexander V. Chernikov case IPFW_TR_ERROR: 9743a845e10SAlexander V. Chernikov px = "error"; 9753a845e10SAlexander V. Chernikov ignored = 1; 9763a845e10SAlexander V. Chernikov break; 9773a845e10SAlexander V. Chernikov case IPFW_TR_NOTFOUND: 9783a845e10SAlexander V. Chernikov px = "notfound"; 9793a845e10SAlexander V. Chernikov ignored = 1; 9803a845e10SAlexander V. Chernikov break; 9813a845e10SAlexander V. Chernikov case IPFW_TR_EXISTS: 9823a845e10SAlexander V. Chernikov px = "exists"; 9833a845e10SAlexander V. Chernikov ignored = 1; 9843a845e10SAlexander V. Chernikov break; 9853a845e10SAlexander V. Chernikov case IPFW_TR_IGNORED: 9863a845e10SAlexander V. Chernikov px = "ignored"; 9873a845e10SAlexander V. Chernikov ignored = 1; 9883a845e10SAlexander V. Chernikov break; 9893a845e10SAlexander V. Chernikov default: 9903a845e10SAlexander V. Chernikov px = "unknown"; 9913a845e10SAlexander V. Chernikov ignored = 1; 9923a845e10SAlexander V. Chernikov } 9933a845e10SAlexander V. Chernikov 9943a845e10SAlexander V. Chernikov if (error != 0 && atomic != 0 && ignored == 0) 9953a845e10SAlexander V. Chernikov printf("%s(reverted): ", px); 9963a845e10SAlexander V. Chernikov else 9973a845e10SAlexander V. Chernikov printf("%s: ", px); 9983a845e10SAlexander V. Chernikov 9993a845e10SAlexander V. Chernikov table_show_entry(&xi, ptent); 10003a845e10SAlexander V. Chernikov } 10013a845e10SAlexander V. Chernikov 10023a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10033a845e10SAlexander V. Chernikov free(tent_buf); 10043a845e10SAlexander V. Chernikov 10053a845e10SAlexander V. Chernikov if (error == 0) 10064c0c07a5SAlexander V. Chernikov return; 100768bde59eSAlexander V. Chernikov /* Get real OS error */ 100868bde59eSAlexander V. Chernikov error = errno; 10094c0c07a5SAlexander V. Chernikov 10104c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 10114c0c07a5SAlexander V. Chernikov switch (error) { 10124c0c07a5SAlexander V. Chernikov case EEXIST: 10134c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 10144c0c07a5SAlexander V. Chernikov break; 10154c0c07a5SAlexander V. Chernikov case EFBIG: 10164c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 10174c0c07a5SAlexander V. Chernikov break; 10184c0c07a5SAlexander V. Chernikov case ESRCH: 10194c0c07a5SAlexander V. Chernikov etxt = "table not found"; 10204c0c07a5SAlexander V. Chernikov break; 10214c0c07a5SAlexander V. Chernikov case ENOENT: 10224c0c07a5SAlexander V. Chernikov etxt = "record not found"; 10234c0c07a5SAlexander V. Chernikov break; 10244f43138aSAlexander V. Chernikov case EACCES: 10254f43138aSAlexander V. Chernikov etxt = "table is locked"; 10264f43138aSAlexander V. Chernikov break; 10274c0c07a5SAlexander V. Chernikov default: 10284c0c07a5SAlexander V. Chernikov etxt = strerror(error); 10294c0c07a5SAlexander V. Chernikov } 10304c0c07a5SAlexander V. Chernikov 10314c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 1032ac35ff17SAlexander V. Chernikov } 1033ac35ff17SAlexander V. Chernikov 103481d3153dSAlexander V. Chernikov static int 103581d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 103681d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 103781d3153dSAlexander V. Chernikov { 103881d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 103981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 10400cba2b28SAlexander V. Chernikov uint8_t type; 10410cba2b28SAlexander V. Chernikov uint32_t vmask; 104281d3153dSAlexander V. Chernikov size_t sz; 104381d3153dSAlexander V. Chernikov 104481d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 104581d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 104681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 104781d3153dSAlexander V. Chernikov 104881d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 104981d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 105081d3153dSAlexander V. Chernikov tent->idx = 1; 105181d3153dSAlexander V. Chernikov 10520cba2b28SAlexander V. Chernikov tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); 105381d3153dSAlexander V. Chernikov oh->ntlv.type = type; 105481d3153dSAlexander V. Chernikov 105581d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 1056b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0) 1057b6462881SAlexander V. Chernikov return (errno); 105881d3153dSAlexander V. Chernikov 105981d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 106081d3153dSAlexander V. Chernikov return (EINVAL); 106181d3153dSAlexander V. Chernikov 106281d3153dSAlexander V. Chernikov *xtent = *tent; 106381d3153dSAlexander V. Chernikov 106481d3153dSAlexander V. Chernikov return (0); 106581d3153dSAlexander V. Chernikov } 106681d3153dSAlexander V. Chernikov 106781d3153dSAlexander V. Chernikov static void 106881d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 106981d3153dSAlexander V. Chernikov { 107081d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 107181d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 1072914bffb6SAlexander V. Chernikov char key[64]; 107381d3153dSAlexander V. Chernikov int error; 107481d3153dSAlexander V. Chernikov 107581d3153dSAlexander V. Chernikov if (ac == 0) 107681d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 107781d3153dSAlexander V. Chernikov 1078914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 1079914bffb6SAlexander V. Chernikov 10803a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 1081914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 108281d3153dSAlexander V. Chernikov 108381d3153dSAlexander V. Chernikov switch (error) { 108481d3153dSAlexander V. Chernikov case 0: 108581d3153dSAlexander V. Chernikov break; 108681d3153dSAlexander V. Chernikov case ESRCH: 108781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 108881d3153dSAlexander V. Chernikov case ENOENT: 108981d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 109081d3153dSAlexander V. Chernikov case ENOTSUP: 109181d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 109281d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 109381d3153dSAlexander V. Chernikov default: 109481d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 109581d3153dSAlexander V. Chernikov } 109681d3153dSAlexander V. Chernikov 109781d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 109881d3153dSAlexander V. Chernikov } 1099ac35ff17SAlexander V. Chernikov 1100ac35ff17SAlexander V. Chernikov static void 1101914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1102914bffb6SAlexander V. Chernikov uint8_t tflags) 1103ac35ff17SAlexander V. Chernikov { 1104914bffb6SAlexander V. Chernikov char *p, *pp; 1105ac35ff17SAlexander V. Chernikov int mask, af; 1106914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 1107914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 1108ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 1109914bffb6SAlexander V. Chernikov uint16_t port; 1110914bffb6SAlexander V. Chernikov struct protoent *pent; 1111914bffb6SAlexander V. Chernikov struct servent *sent; 1112ac35ff17SAlexander V. Chernikov int masklen; 1113ac35ff17SAlexander V. Chernikov 1114ac35ff17SAlexander V. Chernikov masklen = 0; 1115ac35ff17SAlexander V. Chernikov af = 0; 1116ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 1117ac35ff17SAlexander V. Chernikov 1118ac35ff17SAlexander V. Chernikov switch (type) { 1119c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1120ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 1121ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 1122ac35ff17SAlexander V. Chernikov *p = '\0'; 1123ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 1124ac35ff17SAlexander V. Chernikov } 1125ac35ff17SAlexander V. Chernikov 1126ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 1127ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 1128ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 1129ac35ff17SAlexander V. Chernikov p + 1); 1130ac35ff17SAlexander V. Chernikov 1131ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 1132ac35ff17SAlexander V. Chernikov af = AF_INET; 1133ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 1134ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 1135ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 1136ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 1137ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 1138ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 1139ac35ff17SAlexander V. Chernikov p + 1); 1140ac35ff17SAlexander V. Chernikov 1141ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 1142ac35ff17SAlexander V. Chernikov af = AF_INET6; 1143ac35ff17SAlexander V. Chernikov } else { 1144ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 1145ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1146ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1147ac35ff17SAlexander V. Chernikov 1148ac35ff17SAlexander V. Chernikov masklen = 32; 1149c21034b7SAlexander V. Chernikov type = IPFW_TABLE_ADDR; 1150ac35ff17SAlexander V. Chernikov af = AF_INET; 1151ac35ff17SAlexander V. Chernikov } 1152ac35ff17SAlexander V. Chernikov break; 1153ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1154ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 1155ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1156ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 1157ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 1158ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 1159ac35ff17SAlexander V. Chernikov break; 1160b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1161ac35ff17SAlexander V. Chernikov /* Port or any other key */ 1162ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 1163ac35ff17SAlexander V. Chernikov if (*p != '\0') 1164ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 1165ac35ff17SAlexander V. Chernikov 1166ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 1167ac35ff17SAlexander V. Chernikov *pkey = key; 1168ac35ff17SAlexander V. Chernikov masklen = 32; 1169ac35ff17SAlexander V. Chernikov break; 1170914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1171914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1172914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 1173914bffb6SAlexander V. Chernikov af = 0; 1174914bffb6SAlexander V. Chernikov 1175914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6> */ 1176914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1177914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1178914bffb6SAlexander V. Chernikov *p++ = '\0'; 1179914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1180914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1181914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1182914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1183914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1184914bffb6SAlexander V. Chernikov af = AF_INET; 1185914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 1186914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1187914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1188914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1189914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1190914bffb6SAlexander V. Chernikov af = AF_INET6; 1191914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 1192914bffb6SAlexander V. Chernikov } 1193914bffb6SAlexander V. Chernikov 1194914bffb6SAlexander V. Chernikov arg = p; 1195914bffb6SAlexander V. Chernikov } 1196914bffb6SAlexander V. Chernikov 1197914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 1198914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 119935df97d0SAlexander V. Chernikov if (arg == NULL) 120035df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: proto missing"); 1201914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1202914bffb6SAlexander V. Chernikov *p++ = '\0'; 1203914bffb6SAlexander V. Chernikov 1204914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 1205914bffb6SAlexander V. Chernikov if (*pp != '\0') { 1206914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 1207914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 1208914bffb6SAlexander V. Chernikov arg); 1209914bffb6SAlexander V. Chernikov else 1210914bffb6SAlexander V. Chernikov key = pent->p_proto; 1211914bffb6SAlexander V. Chernikov } 1212914bffb6SAlexander V. Chernikov 1213914bffb6SAlexander V. Chernikov if (key > 255) 1214914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 1215914bffb6SAlexander V. Chernikov 1216914bffb6SAlexander V. Chernikov tfe->proto = key; 1217914bffb6SAlexander V. Chernikov 1218914bffb6SAlexander V. Chernikov arg = p; 1219914bffb6SAlexander V. Chernikov } 1220914bffb6SAlexander V. Chernikov 1221914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1222914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 122335df97d0SAlexander V. Chernikov if (arg == NULL) 122435df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: src port missing"); 1225914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1226914bffb6SAlexander V. Chernikov *p++ = '\0'; 1227914bffb6SAlexander V. Chernikov 1228914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1229914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1230914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1231914bffb6SAlexander V. Chernikov arg); 1232914bffb6SAlexander V. Chernikov else 1233914bffb6SAlexander V. Chernikov key = sent->s_port; 1234914bffb6SAlexander V. Chernikov } 1235914bffb6SAlexander V. Chernikov 1236914bffb6SAlexander V. Chernikov tfe->sport = port; 1237914bffb6SAlexander V. Chernikov 1238914bffb6SAlexander V. Chernikov arg = p; 1239914bffb6SAlexander V. Chernikov } 1240914bffb6SAlexander V. Chernikov 1241914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1242914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 124335df97d0SAlexander V. Chernikov if (arg == NULL) 124435df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst ip missing"); 1245914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1246914bffb6SAlexander V. Chernikov *p++ = '\0'; 1247914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1248914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1249914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1250914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1251914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1252914bffb6SAlexander V. Chernikov af = AF_INET; 1253914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 1254914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1255914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1256914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1257914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1258914bffb6SAlexander V. Chernikov af = AF_INET6; 1259914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1260914bffb6SAlexander V. Chernikov } 1261914bffb6SAlexander V. Chernikov 1262914bffb6SAlexander V. Chernikov arg = p; 1263914bffb6SAlexander V. Chernikov } 1264914bffb6SAlexander V. Chernikov 1265914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1266914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 126735df97d0SAlexander V. Chernikov if (arg == NULL) 126835df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst port missing"); 1269914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1270914bffb6SAlexander V. Chernikov *p++ = '\0'; 1271914bffb6SAlexander V. Chernikov 1272914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1273914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1274914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1275914bffb6SAlexander V. Chernikov arg); 1276914bffb6SAlexander V. Chernikov else 1277914bffb6SAlexander V. Chernikov key = sent->s_port; 1278914bffb6SAlexander V. Chernikov } 1279914bffb6SAlexander V. Chernikov 1280914bffb6SAlexander V. Chernikov tfe->dport = port; 1281914bffb6SAlexander V. Chernikov 1282914bffb6SAlexander V. Chernikov arg = p; 1283914bffb6SAlexander V. Chernikov } 1284914bffb6SAlexander V. Chernikov 1285914bffb6SAlexander V. Chernikov tfe->af = af; 1286914bffb6SAlexander V. Chernikov 1287914bffb6SAlexander V. Chernikov break; 1288914bffb6SAlexander V. Chernikov 1289ac35ff17SAlexander V. Chernikov default: 1290ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1291ac35ff17SAlexander V. Chernikov } 1292ac35ff17SAlexander V. Chernikov 1293ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1294ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1295ac35ff17SAlexander V. Chernikov } 1296ac35ff17SAlexander V. Chernikov 12978755aff6SAlexander V. Chernikov /* 12988755aff6SAlexander V. Chernikov * Tries to guess table key type. 12998755aff6SAlexander V. Chernikov * This procedure is used in legacy table auto-create 13008755aff6SAlexander V. Chernikov * code AND in `ipfw -n` ruleset checking. 13018755aff6SAlexander V. Chernikov * 13028755aff6SAlexander V. Chernikov * Imported from old table_fill_xentry() parse code. 13038755aff6SAlexander V. Chernikov */ 13048755aff6SAlexander V. Chernikov static int 13058755aff6SAlexander V. Chernikov guess_key_type(char *key, uint8_t *ptype) 13068755aff6SAlexander V. Chernikov { 13078755aff6SAlexander V. Chernikov char *p; 13088755aff6SAlexander V. Chernikov struct in6_addr addr; 13098755aff6SAlexander V. Chernikov uint32_t kv; 13108755aff6SAlexander V. Chernikov 13118755aff6SAlexander V. Chernikov if (ishexnumber(*key) != 0 || *key == ':') { 13128755aff6SAlexander V. Chernikov /* Remove / if exists */ 13138755aff6SAlexander V. Chernikov if ((p = strchr(key, '/')) != NULL) 13148755aff6SAlexander V. Chernikov *p = '\0'; 13158755aff6SAlexander V. Chernikov 13168755aff6SAlexander V. Chernikov if ((inet_pton(AF_INET, key, &addr) == 1) || 13178755aff6SAlexander V. Chernikov (inet_pton(AF_INET6, key, &addr) == 1)) { 13188755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 13198755aff6SAlexander V. Chernikov if (p != NULL) 13208755aff6SAlexander V. Chernikov *p = '/'; 13218755aff6SAlexander V. Chernikov return (0); 13228755aff6SAlexander V. Chernikov } else { 13238755aff6SAlexander V. Chernikov /* Port or any other key */ 13248755aff6SAlexander V. Chernikov /* Skip non-base 10 entries like 'fa1' */ 13258755aff6SAlexander V. Chernikov kv = strtol(key, &p, 10); 13268755aff6SAlexander V. Chernikov if (*p == '\0') { 13278755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 13288755aff6SAlexander V. Chernikov return (0); 13298755aff6SAlexander V. Chernikov } else if ((p != key) && (*p == '.')) { 13308755aff6SAlexander V. Chernikov /* 13318755aff6SAlexander V. Chernikov * Warn on IPv4 address strings 13328755aff6SAlexander V. Chernikov * which are "valid" for inet_aton() but not 13338755aff6SAlexander V. Chernikov * in inet_pton(). 13348755aff6SAlexander V. Chernikov * 13358755aff6SAlexander V. Chernikov * Typical examples: '10.5' or '10.0.0.05' 13368755aff6SAlexander V. Chernikov */ 13378755aff6SAlexander V. Chernikov return (1); 13388755aff6SAlexander V. Chernikov } 13398755aff6SAlexander V. Chernikov } 13408755aff6SAlexander V. Chernikov } 13418755aff6SAlexander V. Chernikov 13428755aff6SAlexander V. Chernikov if (strchr(key, '.') == NULL) { 13438755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 13448755aff6SAlexander V. Chernikov return (0); 13458755aff6SAlexander V. Chernikov } 13468755aff6SAlexander V. Chernikov 13478755aff6SAlexander V. Chernikov if (lookup_host(key, (struct in_addr *)&addr) != 0) 13488755aff6SAlexander V. Chernikov return (1); 13498755aff6SAlexander V. Chernikov 13508755aff6SAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 13518755aff6SAlexander V. Chernikov return (0); 13528755aff6SAlexander V. Chernikov } 13538755aff6SAlexander V. Chernikov 1354ac35ff17SAlexander V. Chernikov static void 1355ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 13560cba2b28SAlexander V. Chernikov int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) 1357ac35ff17SAlexander V. Chernikov { 13580cba2b28SAlexander V. Chernikov uint8_t type, tflags; 13590cba2b28SAlexander V. Chernikov uint32_t vmask; 1360ac35ff17SAlexander V. Chernikov int error; 1361ac35ff17SAlexander V. Chernikov 1362ac35ff17SAlexander V. Chernikov type = 0; 1363914bffb6SAlexander V. Chernikov tflags = 0; 13640cba2b28SAlexander V. Chernikov vmask = 0; 1365ac35ff17SAlexander V. Chernikov 13663a845e10SAlexander V. Chernikov if (xi->tablename[0] == '\0') 136781d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 13683a845e10SAlexander V. Chernikov else 13693a845e10SAlexander V. Chernikov error = 0; 137081d3153dSAlexander V. Chernikov 137181d3153dSAlexander V. Chernikov if (error == 0) { 13728755aff6SAlexander V. Chernikov if (co.test_only == 0) { 13738755aff6SAlexander V. Chernikov /* Table found */ 137481d3153dSAlexander V. Chernikov type = xi->type; 1375914bffb6SAlexander V. Chernikov tflags = xi->tflags; 13760cba2b28SAlexander V. Chernikov vmask = xi->vmask; 137781d3153dSAlexander V. Chernikov } else { 13788755aff6SAlexander V. Chernikov /* 1379463a577bSEitan Adler * We're running `ipfw -n` 1380463a577bSEitan Adler * Compatibility layer: try to guess key type 13818755aff6SAlexander V. Chernikov * before failing. 13828755aff6SAlexander V. Chernikov */ 13838755aff6SAlexander V. Chernikov if (guess_key_type(key, &type) != 0) { 13848755aff6SAlexander V. Chernikov /* Inknown key */ 13858755aff6SAlexander V. Chernikov errx(EX_USAGE, "Cannot guess " 13868755aff6SAlexander V. Chernikov "key '%s' type", key); 13878755aff6SAlexander V. Chernikov } 13888755aff6SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 13898755aff6SAlexander V. Chernikov } 13908755aff6SAlexander V. Chernikov } else { 139181d3153dSAlexander V. Chernikov if (error != ESRCH) 139281d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 139381d3153dSAlexander V. Chernikov oh->ntlv.name); 139435df97d0SAlexander V. Chernikov if (add == 0) 139535df97d0SAlexander V. Chernikov errx(EX_DATAERR, "Table %s does not exist", 139635df97d0SAlexander V. Chernikov oh->ntlv.name); 1397ac35ff17SAlexander V. Chernikov /* 13988755aff6SAlexander V. Chernikov * Table does not exist 1399463a577bSEitan Adler * Compatibility layer: try to guess key type before failing. 1400ac35ff17SAlexander V. Chernikov */ 14018755aff6SAlexander V. Chernikov if (guess_key_type(key, &type) != 0) { 140281d3153dSAlexander V. Chernikov /* Inknown key */ 140381d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1404db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 140581d3153dSAlexander V. Chernikov } 14068755aff6SAlexander V. Chernikov 14078755aff6SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 1408ac35ff17SAlexander V. Chernikov } 1409ac35ff17SAlexander V. Chernikov 1410914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1411ac35ff17SAlexander V. Chernikov 1412ac35ff17SAlexander V. Chernikov *ptype = type; 14130cba2b28SAlexander V. Chernikov *pvmask = vmask; 14140cba2b28SAlexander V. Chernikov } 14150cba2b28SAlexander V. Chernikov 14160cba2b28SAlexander V. Chernikov static void 14170cba2b28SAlexander V. Chernikov set_legacy_value(uint32_t val, ipfw_table_value *v) 14180cba2b28SAlexander V. Chernikov { 14190cba2b28SAlexander V. Chernikov v->tag = val; 14200cba2b28SAlexander V. Chernikov v->pipe = val; 14210cba2b28SAlexander V. Chernikov v->divert = val; 14220cba2b28SAlexander V. Chernikov v->skipto = val; 14230cba2b28SAlexander V. Chernikov v->netgraph = val; 14240cba2b28SAlexander V. Chernikov v->fib = val; 14250cba2b28SAlexander V. Chernikov v->nat = val; 14260cba2b28SAlexander V. Chernikov v->nh4 = val; 14270cba2b28SAlexander V. Chernikov v->dscp = (uint8_t)val; 14280cba2b28SAlexander V. Chernikov v->limit = val; 1429ac35ff17SAlexander V. Chernikov } 1430ac35ff17SAlexander V. Chernikov 1431ac35ff17SAlexander V. Chernikov static void 1432ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 14330cba2b28SAlexander V. Chernikov uint8_t type, uint32_t vmask) 1434ac35ff17SAlexander V. Chernikov { 14352530ed9eSAndrey V. Elsukov struct addrinfo hints, *res; 1436b7684f4bSMarcelo Araujo uint32_t a4, flag, val; 14370cba2b28SAlexander V. Chernikov ipfw_table_value *v; 14380cba2b28SAlexander V. Chernikov uint32_t i; 1439d91c61c3SAlexander V. Chernikov int dval; 14400cba2b28SAlexander V. Chernikov char *comma, *e, *etype, *n, *p; 1441ac35ff17SAlexander V. Chernikov 14420cba2b28SAlexander V. Chernikov v = &tent->v.value; 14430cba2b28SAlexander V. Chernikov 14440cba2b28SAlexander V. Chernikov /* Compat layer: keep old behavior for legacy value types */ 14450cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 1446adf3b2b9SAlexander V. Chernikov /* Try to interpret as number first */ 14470cba2b28SAlexander V. Chernikov val = strtoul(arg, &p, 0); 14480cba2b28SAlexander V. Chernikov if (*p == '\0') { 14490cba2b28SAlexander V. Chernikov set_legacy_value(val, v); 1450adf3b2b9SAlexander V. Chernikov return; 14510cba2b28SAlexander V. Chernikov } 1452adf3b2b9SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &val) == 1) { 14530cba2b28SAlexander V. Chernikov set_legacy_value(ntohl(val), v); 1454adf3b2b9SAlexander V. Chernikov return; 1455adf3b2b9SAlexander V. Chernikov } 1456adf3b2b9SAlexander V. Chernikov /* Try hostname */ 14570cba2b28SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&val) == 0) { 14580cba2b28SAlexander V. Chernikov set_legacy_value(val, v); 1459adf3b2b9SAlexander V. Chernikov return; 14600cba2b28SAlexander V. Chernikov } 1461adf3b2b9SAlexander V. Chernikov errx(EX_OSERR, "Unable to parse value %s", arg); 14620cba2b28SAlexander V. Chernikov } 14630cba2b28SAlexander V. Chernikov 14640cba2b28SAlexander V. Chernikov /* 14650cba2b28SAlexander V. Chernikov * Shorthands: handle single value if vmask consists 14660cba2b28SAlexander V. Chernikov * of numbers only. e.g.: 14670cba2b28SAlexander V. Chernikov * vmask = "fib,skipto" -> treat input "1" as "1,1" 14680cba2b28SAlexander V. Chernikov */ 14690cba2b28SAlexander V. Chernikov 14700cba2b28SAlexander V. Chernikov n = arg; 14710cba2b28SAlexander V. Chernikov etype = NULL; 14720cba2b28SAlexander V. Chernikov for (i = 1; i < (1 << 31); i *= 2) { 14730cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 14740cba2b28SAlexander V. Chernikov continue; 14750cba2b28SAlexander V. Chernikov vmask &= ~flag; 14760cba2b28SAlexander V. Chernikov 14770cba2b28SAlexander V. Chernikov if ((comma = strchr(n, ',')) != NULL) 14780cba2b28SAlexander V. Chernikov *comma = '\0'; 14790cba2b28SAlexander V. Chernikov 14800cba2b28SAlexander V. Chernikov switch (flag) { 14810cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 14820cba2b28SAlexander V. Chernikov v->tag = strtol(n, &e, 10); 14830cba2b28SAlexander V. Chernikov if (*e != '\0') 14840cba2b28SAlexander V. Chernikov etype = "tag"; 1485ac35ff17SAlexander V. Chernikov break; 14860cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 14870cba2b28SAlexander V. Chernikov v->pipe = strtol(n, &e, 10); 14880cba2b28SAlexander V. Chernikov if (*e != '\0') 14890cba2b28SAlexander V. Chernikov etype = "pipe"; 1490ac35ff17SAlexander V. Chernikov break; 14910cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 14920cba2b28SAlexander V. Chernikov v->divert = strtol(n, &e, 10); 14930cba2b28SAlexander V. Chernikov if (*e != '\0') 14940cba2b28SAlexander V. Chernikov etype = "divert"; 14950cba2b28SAlexander V. Chernikov break; 14960cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 14970cba2b28SAlexander V. Chernikov v->skipto = strtol(n, &e, 10); 14980cba2b28SAlexander V. Chernikov if (*e != '\0') 14990cba2b28SAlexander V. Chernikov etype = "skipto"; 15000cba2b28SAlexander V. Chernikov break; 15010cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 15020cba2b28SAlexander V. Chernikov v->netgraph = strtol(n, &e, 10); 15030cba2b28SAlexander V. Chernikov if (*e != '\0') 15040cba2b28SAlexander V. Chernikov etype = "netgraph"; 15050cba2b28SAlexander V. Chernikov break; 15060cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 15070cba2b28SAlexander V. Chernikov v->fib = strtol(n, &e, 10); 15080cba2b28SAlexander V. Chernikov if (*e != '\0') 15090cba2b28SAlexander V. Chernikov etype = "fib"; 15100cba2b28SAlexander V. Chernikov break; 15110cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 15120cba2b28SAlexander V. Chernikov v->nat = strtol(n, &e, 10); 15130cba2b28SAlexander V. Chernikov if (*e != '\0') 15140cba2b28SAlexander V. Chernikov etype = "nat"; 15150cba2b28SAlexander V. Chernikov break; 15160cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 15170cba2b28SAlexander V. Chernikov v->limit = strtol(n, &e, 10); 15180cba2b28SAlexander V. Chernikov if (*e != '\0') 15190cba2b28SAlexander V. Chernikov etype = "limit"; 15200cba2b28SAlexander V. Chernikov break; 15210cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 15220cba2b28SAlexander V. Chernikov if (strchr(n, '.') != NULL && 15230cba2b28SAlexander V. Chernikov inet_pton(AF_INET, n, &a4) == 1) { 15240cba2b28SAlexander V. Chernikov v->nh4 = ntohl(a4); 15250cba2b28SAlexander V. Chernikov break; 15260cba2b28SAlexander V. Chernikov } 15270cba2b28SAlexander V. Chernikov if (lookup_host(n, (struct in_addr *)&v->nh4) == 0) 15280cba2b28SAlexander V. Chernikov break; 15290cba2b28SAlexander V. Chernikov etype = "ipv4"; 1530ac35ff17SAlexander V. Chernikov break; 1531ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 15320cba2b28SAlexander V. Chernikov if (isalpha(*n)) { 1533d91c61c3SAlexander V. Chernikov if ((dval = match_token(f_ipdscp, n)) != -1) { 1534d91c61c3SAlexander V. Chernikov v->dscp = dval; 1535ac35ff17SAlexander V. Chernikov break; 1536d91c61c3SAlexander V. Chernikov } else 15370cba2b28SAlexander V. Chernikov etype = "DSCP code"; 15380cba2b28SAlexander V. Chernikov } else { 15390cba2b28SAlexander V. Chernikov v->dscp = strtol(n, &e, 10); 15400cba2b28SAlexander V. Chernikov if (v->dscp > 63 || *e != '\0') 15410cba2b28SAlexander V. Chernikov etype = "DSCP value"; 1542ac35ff17SAlexander V. Chernikov } 15430cba2b28SAlexander V. Chernikov break; 15440cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 15452530ed9eSAndrey V. Elsukov if (strchr(n, ':') != NULL) { 15462530ed9eSAndrey V. Elsukov memset(&hints, 0, sizeof(hints)); 15472530ed9eSAndrey V. Elsukov hints.ai_family = AF_INET6; 15482530ed9eSAndrey V. Elsukov hints.ai_flags = AI_NUMERICHOST; 15492530ed9eSAndrey V. Elsukov if (getaddrinfo(n, NULL, &hints, &res) == 0) { 15502530ed9eSAndrey V. Elsukov v->nh6 = ((struct sockaddr_in6 *) 15512530ed9eSAndrey V. Elsukov res->ai_addr)->sin6_addr; 15522530ed9eSAndrey V. Elsukov v->zoneid = ((struct sockaddr_in6 *) 15532530ed9eSAndrey V. Elsukov res->ai_addr)->sin6_scope_id; 15542530ed9eSAndrey V. Elsukov freeaddrinfo(res); 15550cba2b28SAlexander V. Chernikov break; 15562530ed9eSAndrey V. Elsukov } 15572530ed9eSAndrey V. Elsukov } 15580cba2b28SAlexander V. Chernikov etype = "ipv6"; 15590cba2b28SAlexander V. Chernikov break; 15600cba2b28SAlexander V. Chernikov } 15610cba2b28SAlexander V. Chernikov 15620cba2b28SAlexander V. Chernikov if (etype != NULL) 15630cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Unable to parse %s as %s", n, etype); 15640cba2b28SAlexander V. Chernikov 15650cba2b28SAlexander V. Chernikov if (comma != NULL) 15660cba2b28SAlexander V. Chernikov *comma++ = ','; 15670cba2b28SAlexander V. Chernikov 15680cba2b28SAlexander V. Chernikov if ((n = comma) != NULL) 15690cba2b28SAlexander V. Chernikov continue; 15700cba2b28SAlexander V. Chernikov 15710cba2b28SAlexander V. Chernikov /* End of input. */ 15720cba2b28SAlexander V. Chernikov if (vmask != 0) 15730cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Not enough fields inside value"); 15740cba2b28SAlexander V. Chernikov } 1575ac35ff17SAlexander V. Chernikov } 1576f1220db8SAlexander V. Chernikov 1577f1220db8SAlexander V. Chernikov /* 1578f1220db8SAlexander V. Chernikov * Compare table names. 1579f1220db8SAlexander V. Chernikov * Honor number comparison. 1580f1220db8SAlexander V. Chernikov */ 1581f1220db8SAlexander V. Chernikov static int 1582f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1583f1220db8SAlexander V. Chernikov { 1584f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1585f1220db8SAlexander V. Chernikov 1586f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1587f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1588f1220db8SAlexander V. Chernikov 158968394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1590f1220db8SAlexander V. Chernikov } 1591f1220db8SAlexander V. Chernikov 1592f1220db8SAlexander V. Chernikov /* 1593f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1594f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1595f1220db8SAlexander V. Chernikov * Returns 0 on success. 1596f1220db8SAlexander V. Chernikov */ 1597f1220db8SAlexander V. Chernikov static int 1598f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1599f1220db8SAlexander V. Chernikov { 160028ea4fa3SAlexander V. Chernikov ipfw_obj_lheader *olh; 1601f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1602f1220db8SAlexander V. Chernikov size_t sz; 1603f1220db8SAlexander V. Chernikov int i, error; 1604f1220db8SAlexander V. Chernikov 160528ea4fa3SAlexander V. Chernikov /* Start with reasonable default */ 160628ea4fa3SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1607f1220db8SAlexander V. Chernikov 160828ea4fa3SAlexander V. Chernikov for (;;) { 1609f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1610f1220db8SAlexander V. Chernikov return (ENOMEM); 1611f1220db8SAlexander V. Chernikov 1612f1220db8SAlexander V. Chernikov olh->size = sz; 1613b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) { 161428ea4fa3SAlexander V. Chernikov sz = olh->size; 161568bde59eSAlexander V. Chernikov free(olh); 161668bde59eSAlexander V. Chernikov if (errno != ENOMEM) 1617b6462881SAlexander V. Chernikov return (errno); 161868bde59eSAlexander V. Chernikov continue; 1619f1220db8SAlexander V. Chernikov } 1620f1220db8SAlexander V. Chernikov 1621f1220db8SAlexander V. Chernikov if (sort != 0) 1622f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1623f1220db8SAlexander V. Chernikov 1624f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1625f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1626f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1627f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1628f1220db8SAlexander V. Chernikov } 1629f1220db8SAlexander V. Chernikov 1630f1220db8SAlexander V. Chernikov free(olh); 163128ea4fa3SAlexander V. Chernikov break; 163228ea4fa3SAlexander V. Chernikov } 1633f1220db8SAlexander V. Chernikov 1634f1220db8SAlexander V. Chernikov return (0); 1635f1220db8SAlexander V. Chernikov } 1636f1220db8SAlexander V. Chernikov 163728ea4fa3SAlexander V. Chernikov 1638f1220db8SAlexander V. Chernikov /* 1639f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1640720ee730SAlexander V. Chernikov * eXtended format. Allocate buffer large enough 1641720ee730SAlexander V. Chernikov * to store result. Called needs to free it later. 1642f1220db8SAlexander V. Chernikov * 1643f1220db8SAlexander V. Chernikov * Returns 0 on success. 1644f1220db8SAlexander V. Chernikov */ 1645f1220db8SAlexander V. Chernikov static int 1646720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1647f1220db8SAlexander V. Chernikov { 1648720ee730SAlexander V. Chernikov ipfw_obj_header *oh; 1649f1220db8SAlexander V. Chernikov size_t sz; 1650b6462881SAlexander V. Chernikov int c; 1651f1220db8SAlexander V. Chernikov 165281d3153dSAlexander V. Chernikov sz = 0; 1653720ee730SAlexander V. Chernikov oh = NULL; 1654720ee730SAlexander V. Chernikov for (c = 0; c < 8; c++) { 165581d3153dSAlexander V. Chernikov if (sz < i->size) 1656720ee730SAlexander V. Chernikov sz = i->size + 44; 1657720ee730SAlexander V. Chernikov if (oh != NULL) 1658720ee730SAlexander V. Chernikov free(oh); 1659720ee730SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1660720ee730SAlexander V. Chernikov continue; 1661720ee730SAlexander V. Chernikov table_fill_objheader(oh, i); 1662d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 1663b6462881SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) { 1664720ee730SAlexander V. Chernikov *poh = oh; 1665720ee730SAlexander V. Chernikov return (0); 166681d3153dSAlexander V. Chernikov } 1667f1220db8SAlexander V. Chernikov 1668b6462881SAlexander V. Chernikov if (errno != ENOMEM) 1669720ee730SAlexander V. Chernikov break; 1670720ee730SAlexander V. Chernikov } 1671720ee730SAlexander V. Chernikov free(oh); 1672720ee730SAlexander V. Chernikov 1673b6462881SAlexander V. Chernikov return (errno); 1674f1220db8SAlexander V. Chernikov } 1675f1220db8SAlexander V. Chernikov 1676f1220db8SAlexander V. Chernikov /* 1677f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1678f1220db8SAlexander V. Chernikov */ 1679f1220db8SAlexander V. Chernikov static void 1680f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1681f1220db8SAlexander V. Chernikov { 168281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 168381d3153dSAlexander V. Chernikov uint32_t count; 1684f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1685f1220db8SAlexander V. Chernikov 1686f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 168781d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1688f1220db8SAlexander V. Chernikov 1689f1220db8SAlexander V. Chernikov if (need_header) 1690f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1691f1220db8SAlexander V. Chernikov 1692f1220db8SAlexander V. Chernikov count = i->count; 1693f1220db8SAlexander V. Chernikov while (count > 0) { 169481d3153dSAlexander V. Chernikov table_show_entry(i, tent); 169581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 169681d3153dSAlexander V. Chernikov count--; 169781d3153dSAlexander V. Chernikov } 169881d3153dSAlexander V. Chernikov } 169981d3153dSAlexander V. Chernikov 170081d3153dSAlexander V. Chernikov static void 17010cba2b28SAlexander V. Chernikov table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 17020cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip) 17030cba2b28SAlexander V. Chernikov { 17042530ed9eSAndrey V. Elsukov char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; 17052530ed9eSAndrey V. Elsukov struct sockaddr_in6 sa6; 17060cba2b28SAlexander V. Chernikov uint32_t flag, i, l; 17070cba2b28SAlexander V. Chernikov size_t sz; 17080cba2b28SAlexander V. Chernikov struct in_addr a4; 17090cba2b28SAlexander V. Chernikov 17100cba2b28SAlexander V. Chernikov sz = bufsize; 17110cba2b28SAlexander V. Chernikov 17120cba2b28SAlexander V. Chernikov /* 17130cba2b28SAlexander V. Chernikov * Some shorthands for printing values: 17140cba2b28SAlexander V. Chernikov * legacy assumes all values are equal, so keep the first one. 17150cba2b28SAlexander V. Chernikov */ 17160cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 17170cba2b28SAlexander V. Chernikov if (print_ip != 0) { 17180cba2b28SAlexander V. Chernikov flag = htonl(v->tag); 17190cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &flag, buf, sz); 17200cba2b28SAlexander V. Chernikov } else 17210cba2b28SAlexander V. Chernikov snprintf(buf, sz, "%u", v->tag); 17220cba2b28SAlexander V. Chernikov return; 17230cba2b28SAlexander V. Chernikov } 17240cba2b28SAlexander V. Chernikov 17250cba2b28SAlexander V. Chernikov for (i = 1; i < (1 << 31); i *= 2) { 17260cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 17270cba2b28SAlexander V. Chernikov continue; 17280cba2b28SAlexander V. Chernikov l = 0; 17290cba2b28SAlexander V. Chernikov 17300cba2b28SAlexander V. Chernikov switch (flag) { 17310cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 17320cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->tag); 17330cba2b28SAlexander V. Chernikov break; 17340cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 17350cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->pipe); 17360cba2b28SAlexander V. Chernikov break; 17370cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 17380cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->divert); 17390cba2b28SAlexander V. Chernikov break; 17400cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 17410cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->skipto); 17420cba2b28SAlexander V. Chernikov break; 17430cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 17440cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->netgraph); 17450cba2b28SAlexander V. Chernikov break; 17460cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 17470cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->fib); 17480cba2b28SAlexander V. Chernikov break; 17490cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 17500cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->nat); 17510cba2b28SAlexander V. Chernikov break; 17520cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 17530cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->limit); 17540cba2b28SAlexander V. Chernikov break; 17550cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 17560cba2b28SAlexander V. Chernikov a4.s_addr = htonl(v->nh4); 17570cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); 17580cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 17590cba2b28SAlexander V. Chernikov break; 17600cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 17610cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->dscp); 17620cba2b28SAlexander V. Chernikov break; 17630cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 17642530ed9eSAndrey V. Elsukov sa6.sin6_family = AF_INET6; 17652530ed9eSAndrey V. Elsukov sa6.sin6_len = sizeof(sa6); 17662530ed9eSAndrey V. Elsukov sa6.sin6_addr = v->nh6; 17672530ed9eSAndrey V. Elsukov sa6.sin6_port = 0; 17682530ed9eSAndrey V. Elsukov sa6.sin6_scope_id = v->zoneid; 17692530ed9eSAndrey V. Elsukov if (getnameinfo((const struct sockaddr *)&sa6, 17702530ed9eSAndrey V. Elsukov sa6.sin6_len, abuf, sizeof(abuf), NULL, 0, 17712530ed9eSAndrey V. Elsukov NI_NUMERICHOST) == 0) 17720cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 17730cba2b28SAlexander V. Chernikov break; 17740cba2b28SAlexander V. Chernikov } 17750cba2b28SAlexander V. Chernikov 17760cba2b28SAlexander V. Chernikov buf += l; 17770cba2b28SAlexander V. Chernikov sz -= l; 17780cba2b28SAlexander V. Chernikov } 17790cba2b28SAlexander V. Chernikov 17800cba2b28SAlexander V. Chernikov if (sz != bufsize) 17810cba2b28SAlexander V. Chernikov *(buf - 1) = '\0'; 17820cba2b28SAlexander V. Chernikov } 17830cba2b28SAlexander V. Chernikov 17840cba2b28SAlexander V. Chernikov static void 178581d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 178681d3153dSAlexander V. Chernikov { 17870cba2b28SAlexander V. Chernikov char *comma, tbuf[128], pval[128]; 1788914bffb6SAlexander V. Chernikov void *paddr; 1789914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 179081d3153dSAlexander V. Chernikov 17910cba2b28SAlexander V. Chernikov table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, 17920cba2b28SAlexander V. Chernikov co.do_value_as_ip); 1793914bffb6SAlexander V. Chernikov 1794f1220db8SAlexander V. Chernikov switch (i->type) { 1795c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1796f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 179781d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1798914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1799f1220db8SAlexander V. Chernikov break; 1800f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1801f1220db8SAlexander V. Chernikov /* Interface names */ 1802914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1803b23d5de9SAlexander V. Chernikov break; 1804b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1805b23d5de9SAlexander V. Chernikov /* numbers */ 1806914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1807b23d5de9SAlexander V. Chernikov break; 1808914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1809914bffb6SAlexander V. Chernikov /* flows */ 1810914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1811914bffb6SAlexander V. Chernikov comma = ""; 1812914bffb6SAlexander V. Chernikov 1813914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1814914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1815914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1816914bffb6SAlexander V. Chernikov else 1817914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1818914bffb6SAlexander V. Chernikov 1819914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1820914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1821914bffb6SAlexander V. Chernikov comma = ","; 1822914bffb6SAlexander V. Chernikov } 1823914bffb6SAlexander V. Chernikov 1824914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1825914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1826914bffb6SAlexander V. Chernikov comma = ","; 1827914bffb6SAlexander V. Chernikov } 1828914bffb6SAlexander V. Chernikov 1829914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1830914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1831914bffb6SAlexander V. Chernikov comma = ","; 1832914bffb6SAlexander V. Chernikov } 1833914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1834914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1835914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1836914bffb6SAlexander V. Chernikov else 1837914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1838914bffb6SAlexander V. Chernikov 1839914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1840914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1841914bffb6SAlexander V. Chernikov comma = ","; 1842914bffb6SAlexander V. Chernikov } 1843914bffb6SAlexander V. Chernikov 1844914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1845914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1846914bffb6SAlexander V. Chernikov comma = ","; 1847914bffb6SAlexander V. Chernikov } 1848914bffb6SAlexander V. Chernikov 1849914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1850f1220db8SAlexander V. Chernikov } 1851f1220db8SAlexander V. Chernikov } 1852f1220db8SAlexander V. Chernikov 18539d099b4fSAlexander V. Chernikov static int 18540cba2b28SAlexander V. Chernikov table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) 18559d099b4fSAlexander V. Chernikov { 18569d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 18579d099b4fSAlexander V. Chernikov size_t sz; 18589d099b4fSAlexander V. Chernikov 18599d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 18609d099b4fSAlexander V. Chernikov sz = sizeof(req); 18619d099b4fSAlexander V. Chernikov 1862b6462881SAlexander V. Chernikov if (do_get3(opcode, &req.opheader, &sz) != 0) 1863b6462881SAlexander V. Chernikov if (errno != ENOMEM) 1864b6462881SAlexander V. Chernikov return (errno); 18659d099b4fSAlexander V. Chernikov 18669d099b4fSAlexander V. Chernikov sz = req.size; 18679d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 18689d099b4fSAlexander V. Chernikov return (ENOMEM); 18699d099b4fSAlexander V. Chernikov 18709d099b4fSAlexander V. Chernikov olh->size = sz; 1871b6462881SAlexander V. Chernikov if (do_get3(opcode, &olh->opheader, &sz) != 0) { 18729d099b4fSAlexander V. Chernikov free(olh); 1873b6462881SAlexander V. Chernikov return (errno); 18749d099b4fSAlexander V. Chernikov } 18759d099b4fSAlexander V. Chernikov 18769d099b4fSAlexander V. Chernikov *polh = olh; 18779d099b4fSAlexander V. Chernikov return (0); 18789d099b4fSAlexander V. Chernikov } 18799d099b4fSAlexander V. Chernikov 18800cba2b28SAlexander V. Chernikov static int 18810cba2b28SAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 18820cba2b28SAlexander V. Chernikov { 18830cba2b28SAlexander V. Chernikov 18840cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); 18850cba2b28SAlexander V. Chernikov } 18860cba2b28SAlexander V. Chernikov 18870cba2b28SAlexander V. Chernikov static int 18880cba2b28SAlexander V. Chernikov table_do_get_vlist(ipfw_obj_lheader **polh) 18890cba2b28SAlexander V. Chernikov { 18900cba2b28SAlexander V. Chernikov 18910cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); 18920cba2b28SAlexander V. Chernikov } 18930cba2b28SAlexander V. Chernikov 18949d099b4fSAlexander V. Chernikov void 18959d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 18969d099b4fSAlexander V. Chernikov { 18979d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 18989d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 18999d099b4fSAlexander V. Chernikov int error, i; 19009d099b4fSAlexander V. Chernikov const char *atype; 19019d099b4fSAlexander V. Chernikov 19029d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 19039d099b4fSAlexander V. Chernikov if (error != 0) 19049d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 19059d099b4fSAlexander V. Chernikov 19069d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 19079d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 19089d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 19099d099b4fSAlexander V. Chernikov atype = "unknown"; 19108ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 19118ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 19129d099b4fSAlexander V. Chernikov 19139d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 19149d099b4fSAlexander V. Chernikov } 19159d099b4fSAlexander V. Chernikov 19169d099b4fSAlexander V. Chernikov free(olh); 19179d099b4fSAlexander V. Chernikov } 19189d099b4fSAlexander V. Chernikov 19190cba2b28SAlexander V. Chernikov 19200cba2b28SAlexander V. Chernikov /* Copy of current kernel table_value structure */ 19210cba2b28SAlexander V. Chernikov struct _table_value { 19220cba2b28SAlexander V. Chernikov uint32_t tag; /* O_TAG/O_TAGGED */ 19230cba2b28SAlexander V. Chernikov uint32_t pipe; /* O_PIPE/O_QUEUE */ 19240cba2b28SAlexander V. Chernikov uint16_t divert; /* O_DIVERT/O_TEE */ 19250cba2b28SAlexander V. Chernikov uint16_t skipto; /* skipto, CALLRET */ 19260cba2b28SAlexander V. Chernikov uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ 19270cba2b28SAlexander V. Chernikov uint32_t fib; /* O_SETFIB */ 19280cba2b28SAlexander V. Chernikov uint32_t nat; /* O_NAT */ 19290cba2b28SAlexander V. Chernikov uint32_t nh4; 19300cba2b28SAlexander V. Chernikov uint8_t dscp; 19312530ed9eSAndrey V. Elsukov uint8_t spare0; 19322530ed9eSAndrey V. Elsukov uint16_t spare1; 19330cba2b28SAlexander V. Chernikov /* -- 32 bytes -- */ 19340cba2b28SAlexander V. Chernikov struct in6_addr nh6; 19350cba2b28SAlexander V. Chernikov uint32_t limit; /* O_LIMIT */ 19362530ed9eSAndrey V. Elsukov uint32_t zoneid; 19370cba2b28SAlexander V. Chernikov uint64_t refcnt; /* Number of references */ 19380cba2b28SAlexander V. Chernikov }; 19390cba2b28SAlexander V. Chernikov 19400cba2b28SAlexander V. Chernikov int 19410cba2b28SAlexander V. Chernikov compare_values(const void *_a, const void *_b) 19420cba2b28SAlexander V. Chernikov { 19430cba2b28SAlexander V. Chernikov struct _table_value *a, *b; 19440cba2b28SAlexander V. Chernikov 19450cba2b28SAlexander V. Chernikov a = (struct _table_value *)_a; 19460cba2b28SAlexander V. Chernikov b = (struct _table_value *)_b; 19470cba2b28SAlexander V. Chernikov 19480cba2b28SAlexander V. Chernikov if (a->spare1 < b->spare1) 19490cba2b28SAlexander V. Chernikov return (-1); 19500cba2b28SAlexander V. Chernikov else if (a->spare1 > b->spare1) 19510cba2b28SAlexander V. Chernikov return (1); 19520cba2b28SAlexander V. Chernikov 19530cba2b28SAlexander V. Chernikov return (0); 19540cba2b28SAlexander V. Chernikov } 19550cba2b28SAlexander V. Chernikov 19560cba2b28SAlexander V. Chernikov void 19570cba2b28SAlexander V. Chernikov ipfw_list_values(int ac, char *av[]) 19580cba2b28SAlexander V. Chernikov { 19590cba2b28SAlexander V. Chernikov ipfw_obj_lheader *olh; 19600cba2b28SAlexander V. Chernikov struct _table_value *v; 19610cba2b28SAlexander V. Chernikov int error, i; 19620cba2b28SAlexander V. Chernikov uint32_t vmask; 19630cba2b28SAlexander V. Chernikov char buf[128]; 19640cba2b28SAlexander V. Chernikov 19650cba2b28SAlexander V. Chernikov error = table_do_get_vlist(&olh); 19660cba2b28SAlexander V. Chernikov if (error != 0) 19670cba2b28SAlexander V. Chernikov err(EX_OSERR, "Unable to request value list"); 19680cba2b28SAlexander V. Chernikov 19690cba2b28SAlexander V. Chernikov vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ 19700cba2b28SAlexander V. Chernikov 19710cba2b28SAlexander V. Chernikov table_print_valheader(buf, sizeof(buf), vmask); 19720cba2b28SAlexander V. Chernikov printf("HEADER: %s\n", buf); 19730cba2b28SAlexander V. Chernikov v = (struct _table_value *)(olh + 1); 19740cba2b28SAlexander V. Chernikov qsort(v, olh->count, olh->objsize, compare_values); 19750cba2b28SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 19760cba2b28SAlexander V. Chernikov table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, 19770cba2b28SAlexander V. Chernikov vmask, 0); 1978d3de6c1dSAlexander V. Chernikov printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf); 19790cba2b28SAlexander V. Chernikov v = (struct _table_value *)((caddr_t)v + olh->objsize); 19800cba2b28SAlexander V. Chernikov } 19810cba2b28SAlexander V. Chernikov 19820cba2b28SAlexander V. Chernikov free(olh); 19830cba2b28SAlexander V. Chernikov } 19840cba2b28SAlexander V. Chernikov 19856c2997ffSAlexander V. Chernikov int 1986*2acdf79fSAndrey V. Elsukov table_check_name(const char *tablename) 19876c2997ffSAlexander V. Chernikov { 19886c2997ffSAlexander V. Chernikov 1989*2acdf79fSAndrey V. Elsukov if (ipfw_check_object_name(tablename) != 0) 19906c2997ffSAlexander V. Chernikov return (EINVAL); 1991ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1992ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1993ac35ff17SAlexander V. Chernikov return (EINVAL); 19946c2997ffSAlexander V. Chernikov return (0); 19956c2997ffSAlexander V. Chernikov } 19966c2997ffSAlexander V. Chernikov 1997