1f1220db8SAlexander V. Chernikov /* 2f1220db8SAlexander V. Chernikov * Copyright (c) 2002-2003 Luigi Rizzo 3f1220db8SAlexander V. Chernikov * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4f1220db8SAlexander V. Chernikov * Copyright (c) 1994 Ugen J.S.Antsilevich 5f1220db8SAlexander V. Chernikov * 6f1220db8SAlexander V. Chernikov * Idea and grammar partially left from: 7f1220db8SAlexander V. Chernikov * Copyright (c) 1993 Daniel Boulet 8f1220db8SAlexander V. Chernikov * 9f1220db8SAlexander V. Chernikov * Redistribution and use in source forms, with and without modification, 10f1220db8SAlexander V. Chernikov * are permitted provided that this entire comment appears intact. 11f1220db8SAlexander V. Chernikov * 12f1220db8SAlexander V. Chernikov * Redistribution in binary form may occur without any restrictions. 13f1220db8SAlexander V. Chernikov * Obviously, it would be nice if you gave credit where credit is due 14f1220db8SAlexander V. Chernikov * but requiring it would be too onerous. 15f1220db8SAlexander V. Chernikov * 16f1220db8SAlexander V. Chernikov * This software is provided ``AS IS'' without any warranties of any kind. 17f1220db8SAlexander V. Chernikov * 18f1220db8SAlexander V. Chernikov * in-kernel tables support 19f1220db8SAlexander V. Chernikov * 20f1220db8SAlexander V. Chernikov * $FreeBSD: projects/ipfw/sbin/ipfw/ipfw2.c 267467 2014-06-14 10:58:39Z melifaro $ 21f1220db8SAlexander V. Chernikov */ 22f1220db8SAlexander V. Chernikov 23f1220db8SAlexander V. Chernikov 24f1220db8SAlexander V. Chernikov #include <sys/types.h> 25f1220db8SAlexander V. Chernikov #include <sys/param.h> 26f1220db8SAlexander V. Chernikov #include <sys/socket.h> 27f1220db8SAlexander V. Chernikov #include <sys/sysctl.h> 28f1220db8SAlexander V. Chernikov 29f1220db8SAlexander V. Chernikov #include <ctype.h> 30f1220db8SAlexander V. Chernikov #include <err.h> 31f1220db8SAlexander V. Chernikov #include <errno.h> 32f1220db8SAlexander V. Chernikov #include <netdb.h> 33f1220db8SAlexander V. Chernikov #include <stdio.h> 34f1220db8SAlexander V. Chernikov #include <stdlib.h> 35f1220db8SAlexander V. Chernikov #include <string.h> 36f1220db8SAlexander V. Chernikov #include <sysexits.h> 37f1220db8SAlexander V. Chernikov 38f1220db8SAlexander V. Chernikov #include <net/if.h> 39f1220db8SAlexander V. Chernikov #include <netinet/in.h> 40f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h> 41f1220db8SAlexander V. Chernikov #include <arpa/inet.h> 42f1220db8SAlexander V. Chernikov 43f1220db8SAlexander V. Chernikov #include "ipfw2.h" 44f1220db8SAlexander V. Chernikov 45f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header); 46ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 473a845e10SAlexander V. Chernikov int add, int quiet, int update, int atomic); 48ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh); 49ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh); 50ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 51adf3b2b9SAlexander V. Chernikov static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i); 5246d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second); 53adf3b2b9SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 54adf3b2b9SAlexander V. Chernikov static void table_modify(ipfw_obj_header *oh, int ac, char *av[]); 55adf3b2b9SAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 564f43138aSAlexander V. Chernikov static void table_lock(ipfw_obj_header *oh, int lock); 5746d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second); 58ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 59f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 60ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, 61ac35ff17SAlexander V. Chernikov uint16_t uidx); 62f1220db8SAlexander V. Chernikov 63f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 64f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 65720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); 66f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 6781d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 68f1220db8SAlexander V. Chernikov 69ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 70*0cba2b28SAlexander V. Chernikov char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi); 71ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 72*0cba2b28SAlexander V. Chernikov char *arg, uint8_t type, uint32_t vmask); 73*0cba2b28SAlexander V. Chernikov static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 74*0cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip); 75ac35ff17SAlexander V. Chernikov 76f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 77f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 78f1220db8SAlexander V. Chernikov 79f1220db8SAlexander V. Chernikov #ifndef s6_addr32 80f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 81f1220db8SAlexander V. Chernikov #endif 82f1220db8SAlexander V. Chernikov 83ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 84c21034b7SAlexander V. Chernikov { "addr", IPFW_TABLE_ADDR }, 85ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 86b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 87914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 88ac35ff17SAlexander V. Chernikov { NULL, 0 } 89ac35ff17SAlexander V. Chernikov }; 90ac35ff17SAlexander V. Chernikov 91ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 92*0cba2b28SAlexander V. Chernikov { "skipto", IPFW_VTYPE_SKIPTO }, 93*0cba2b28SAlexander V. Chernikov { "pipe", IPFW_VTYPE_PIPE }, 94*0cba2b28SAlexander V. Chernikov { "fib", IPFW_VTYPE_FIB }, 95*0cba2b28SAlexander V. Chernikov { "nat", IPFW_VTYPE_NAT }, 96*0cba2b28SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 97*0cba2b28SAlexander V. Chernikov { "tag", IPFW_VTYPE_TAG }, 98*0cba2b28SAlexander V. Chernikov { "divert", IPFW_VTYPE_DIVERT }, 99*0cba2b28SAlexander V. Chernikov { "netgraph", IPFW_VTYPE_NETGRAPH }, 100*0cba2b28SAlexander V. Chernikov { "limit", IPFW_VTYPE_LIMIT }, 101*0cba2b28SAlexander V. Chernikov { "ipv4", IPFW_VTYPE_NH4 }, 102*0cba2b28SAlexander V. Chernikov { "ipv6", IPFW_VTYPE_NH6 }, 103adf3b2b9SAlexander V. Chernikov { NULL, 0 } 104adf3b2b9SAlexander V. Chernikov }; 105adf3b2b9SAlexander V. Chernikov 106ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 107ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 108ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 10946d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 110ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 111ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 112adf3b2b9SAlexander V. Chernikov { "modify", TOK_MODIFY }, 11346d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 114ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 115358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 116ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 11781d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 1183a845e10SAlexander V. Chernikov { "atomic", TOK_ATOMIC }, 1194f43138aSAlexander V. Chernikov { "lock", TOK_LOCK }, 1204f43138aSAlexander V. Chernikov { "unlock", TOK_UNLOCK }, 121ac35ff17SAlexander V. Chernikov { NULL, 0 } 122ac35ff17SAlexander V. Chernikov }; 123ac35ff17SAlexander V. Chernikov 124f1220db8SAlexander V. Chernikov static int 125f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 126f1220db8SAlexander V. Chernikov { 127f1220db8SAlexander V. Chernikov struct hostent *he; 128f1220db8SAlexander V. Chernikov 129f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 130f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 131f1220db8SAlexander V. Chernikov return(-1); 132f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 133f1220db8SAlexander V. Chernikov } 134f1220db8SAlexander V. Chernikov return(0); 135f1220db8SAlexander V. Chernikov } 136f1220db8SAlexander V. Chernikov 137be695df9SAlexander V. Chernikov static int 138be695df9SAlexander V. Chernikov get_token(struct _s_x *table, char *string, char *errbase) 139be695df9SAlexander V. Chernikov { 140be695df9SAlexander V. Chernikov int tcmd; 141be695df9SAlexander V. Chernikov 142be695df9SAlexander V. Chernikov if ((tcmd = match_token_relaxed(table, string)) < 0) 143be695df9SAlexander V. Chernikov errx(EX_USAGE, "%s %s %s", 144be695df9SAlexander V. Chernikov (tcmd == 0) ? "invalid" : "ambiguous", errbase, string); 145be695df9SAlexander V. Chernikov 146be695df9SAlexander V. Chernikov return (tcmd); 147be695df9SAlexander V. Chernikov } 148be695df9SAlexander V. Chernikov 149f1220db8SAlexander V. Chernikov /* 150f1220db8SAlexander V. Chernikov * This one handles all table-related commands 151ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 152be695df9SAlexander V. Chernikov * ipfw table NAME modify ... 153ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 154be695df9SAlexander V. Chernikov * ipfw table NAME swap NAME 155be695df9SAlexander V. Chernikov * ipfw table NAME lock 156be695df9SAlexander V. Chernikov * ipfw table NAME unlock 157ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 158be695df9SAlexander V. Chernikov * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] .. 159be695df9SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] [addr[/masklen]] .. 160be695df9SAlexander V. Chernikov * ipfw table NAME lookup addr 161ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 162ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 163ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 164be695df9SAlexander V. Chernikov * ipfw table {NAME | all} detail 165f1220db8SAlexander V. Chernikov */ 166f1220db8SAlexander V. Chernikov void 167f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 168f1220db8SAlexander V. Chernikov { 169ac35ff17SAlexander V. Chernikov int do_add, is_all; 1703a845e10SAlexander V. Chernikov int atomic, error, tcmd; 171ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 172ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 173f1220db8SAlexander V. Chernikov char *tablename; 174ac35ff17SAlexander V. Chernikov uint32_t set; 175358b9d09SAlexander V. Chernikov void *arg; 176f1220db8SAlexander V. Chernikov 177ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 178ac35ff17SAlexander V. Chernikov is_all = 0; 179ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 180ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 181ac35ff17SAlexander V. Chernikov else 182ac35ff17SAlexander V. Chernikov set = 0; 183f1220db8SAlexander V. Chernikov 184f1220db8SAlexander V. Chernikov ac--; av++; 1859d099b4fSAlexander V. Chernikov NEED1("table needs name"); 186f1220db8SAlexander V. Chernikov tablename = *av; 187f1220db8SAlexander V. Chernikov 188ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 189ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 190ac35ff17SAlexander V. Chernikov oh.idx = 1; 191ac35ff17SAlexander V. Chernikov } else { 192ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 193ac35ff17SAlexander V. Chernikov is_all = 1; 194ac35ff17SAlexander V. Chernikov else 195ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 196ac35ff17SAlexander V. Chernikov } 197ac35ff17SAlexander V. Chernikov ac--; av++; 1989d099b4fSAlexander V. Chernikov NEED1("table needs command"); 199ac35ff17SAlexander V. Chernikov 200be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 2013a845e10SAlexander V. Chernikov /* Check if atomic operation was requested */ 2023a845e10SAlexander V. Chernikov atomic = 0; 2033a845e10SAlexander V. Chernikov if (tcmd == TOK_ATOMIC) { 2043a845e10SAlexander V. Chernikov ac--; av++; 2053a845e10SAlexander V. Chernikov NEED1("atomic needs command"); 206be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 2073a845e10SAlexander V. Chernikov switch (tcmd) { 2083a845e10SAlexander V. Chernikov case TOK_ADD: 2093a845e10SAlexander V. Chernikov break; 2103a845e10SAlexander V. Chernikov default: 2113a845e10SAlexander V. Chernikov errx(EX_USAGE, "atomic is not compatible with %s", *av); 2123a845e10SAlexander V. Chernikov } 2133a845e10SAlexander V. Chernikov atomic = 1; 2143a845e10SAlexander V. Chernikov } 215ac35ff17SAlexander V. Chernikov 216ac35ff17SAlexander V. Chernikov switch (tcmd) { 217ac35ff17SAlexander V. Chernikov case TOK_LIST: 218ac35ff17SAlexander V. Chernikov case TOK_INFO: 219358b9d09SAlexander V. Chernikov case TOK_DETAIL: 220ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 221ac35ff17SAlexander V. Chernikov break; 222ac35ff17SAlexander V. Chernikov default: 223ac35ff17SAlexander V. Chernikov if (is_all != 0) 224ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 225ac35ff17SAlexander V. Chernikov } 226ac35ff17SAlexander V. Chernikov 227ac35ff17SAlexander V. Chernikov switch (tcmd) { 228ac35ff17SAlexander V. Chernikov case TOK_ADD: 229ac35ff17SAlexander V. Chernikov case TOK_DEL: 230f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 231f1220db8SAlexander V. Chernikov ac--; av++; 2323a845e10SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet, 2333a845e10SAlexander V. Chernikov co.do_quiet, atomic); 234ac35ff17SAlexander V. Chernikov break; 235ac35ff17SAlexander V. Chernikov case TOK_CREATE: 236f1220db8SAlexander V. Chernikov ac--; av++; 237ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 238ac35ff17SAlexander V. Chernikov break; 239adf3b2b9SAlexander V. Chernikov case TOK_MODIFY: 240adf3b2b9SAlexander V. Chernikov ac--; av++; 241adf3b2b9SAlexander V. Chernikov table_modify(&oh, ac, av); 242adf3b2b9SAlexander V. Chernikov break; 243ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 244ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 245ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 246ac35ff17SAlexander V. Chernikov break; 247ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 248f1220db8SAlexander V. Chernikov if (is_all == 0) { 249ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 250f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 251f1220db8SAlexander V. Chernikov tablename); 252f1220db8SAlexander V. Chernikov } else { 253ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 254f1220db8SAlexander V. Chernikov if (error != 0) 255f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 256f1220db8SAlexander V. Chernikov } 257ac35ff17SAlexander V. Chernikov break; 25846d52008SAlexander V. Chernikov case TOK_SWAP: 25946d52008SAlexander V. Chernikov ac--; av++; 26046d52008SAlexander V. Chernikov NEED1("second table name required"); 26146d52008SAlexander V. Chernikov table_swap(&oh, *av); 26246d52008SAlexander V. Chernikov break; 2634f43138aSAlexander V. Chernikov case TOK_LOCK: 2644f43138aSAlexander V. Chernikov case TOK_UNLOCK: 2654f43138aSAlexander V. Chernikov table_lock(&oh, (tcmd == TOK_LOCK)); 2664f43138aSAlexander V. Chernikov break; 267358b9d09SAlexander V. Chernikov case TOK_DETAIL: 268ac35ff17SAlexander V. Chernikov case TOK_INFO: 269358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 270f1220db8SAlexander V. Chernikov if (is_all == 0) { 271ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 272f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 273358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 274f1220db8SAlexander V. Chernikov } else { 275358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 276f1220db8SAlexander V. Chernikov if (error != 0) 277f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 278f1220db8SAlexander V. Chernikov } 279ac35ff17SAlexander V. Chernikov break; 280ac35ff17SAlexander V. Chernikov case TOK_LIST: 281ac35ff17SAlexander V. Chernikov if (is_all == 0) { 282ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 283ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 284ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 285ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 286f1220db8SAlexander V. Chernikov } else { 287ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 288ac35ff17SAlexander V. Chernikov if (error != 0) 289ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 290f1220db8SAlexander V. Chernikov } 291ac35ff17SAlexander V. Chernikov break; 29281d3153dSAlexander V. Chernikov case TOK_LOOKUP: 29381d3153dSAlexander V. Chernikov ac--; av++; 29481d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 29581d3153dSAlexander V. Chernikov break; 296f1220db8SAlexander V. Chernikov } 297f1220db8SAlexander V. Chernikov } 298f1220db8SAlexander V. Chernikov 299f1220db8SAlexander V. Chernikov static void 300ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 301f1220db8SAlexander V. Chernikov { 302f1220db8SAlexander V. Chernikov 303563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 304f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 305f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 306ac35ff17SAlexander V. Chernikov ntlv->set = set; 307f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 308f1220db8SAlexander V. Chernikov } 309f1220db8SAlexander V. Chernikov 310f1220db8SAlexander V. Chernikov static void 311f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 312f1220db8SAlexander V. Chernikov { 313f1220db8SAlexander V. Chernikov 314f1220db8SAlexander V. Chernikov oh->idx = 1; 31581d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 316ac35ff17SAlexander V. Chernikov } 317ac35ff17SAlexander V. Chernikov 318ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 319ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 320ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 321ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 3224c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 3234f43138aSAlexander V. Chernikov { "locked", TOK_LOCK }, 324ac35ff17SAlexander V. Chernikov { NULL, 0 } 325ac35ff17SAlexander V. Chernikov }; 326ac35ff17SAlexander V. Chernikov 327914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 328914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 329914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 330914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 331914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 332914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 333914bffb6SAlexander V. Chernikov { NULL, 0 } 334914bffb6SAlexander V. Chernikov }; 335914bffb6SAlexander V. Chernikov 336914bffb6SAlexander V. Chernikov int 337914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 338914bffb6SAlexander V. Chernikov { 339*0cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 340*0cba2b28SAlexander V. Chernikov char *e; 341914bffb6SAlexander V. Chernikov 342914bffb6SAlexander V. Chernikov /* Parse type options */ 343914bffb6SAlexander V. Chernikov switch(ttype) { 344914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 345914bffb6SAlexander V. Chernikov fset = fclear = 0; 346*0cba2b28SAlexander V. Chernikov if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0) 347*0cba2b28SAlexander V. Chernikov errx(EX_USAGE, 348*0cba2b28SAlexander V. Chernikov "unable to parse flow option %s", e); 349914bffb6SAlexander V. Chernikov *tflags = fset; 350914bffb6SAlexander V. Chernikov break; 351914bffb6SAlexander V. Chernikov default: 352914bffb6SAlexander V. Chernikov return (EX_USAGE); 353914bffb6SAlexander V. Chernikov } 354914bffb6SAlexander V. Chernikov 355914bffb6SAlexander V. Chernikov return (0); 356914bffb6SAlexander V. Chernikov } 357914bffb6SAlexander V. Chernikov 358914bffb6SAlexander V. Chernikov void 359914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 360914bffb6SAlexander V. Chernikov { 361914bffb6SAlexander V. Chernikov const char *tname; 362914bffb6SAlexander V. Chernikov int l; 363914bffb6SAlexander V. Chernikov 364914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 365914bffb6SAlexander V. Chernikov tname = "unknown"; 366914bffb6SAlexander V. Chernikov 367914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 368914bffb6SAlexander V. Chernikov tbuf += l; 369914bffb6SAlexander V. Chernikov size -= l; 370914bffb6SAlexander V. Chernikov 371914bffb6SAlexander V. Chernikov switch(type) { 372914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 373914bffb6SAlexander V. Chernikov if (tflags != 0) { 374914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 375914bffb6SAlexander V. Chernikov l--; 376914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 377914bffb6SAlexander V. Chernikov } 378914bffb6SAlexander V. Chernikov break; 379914bffb6SAlexander V. Chernikov } 380914bffb6SAlexander V. Chernikov } 381914bffb6SAlexander V. Chernikov 382ac35ff17SAlexander V. Chernikov /* 383ac35ff17SAlexander V. Chernikov * Creates new table 384ac35ff17SAlexander V. Chernikov * 385c21034b7SAlexander V. Chernikov * ipfw table NAME create [ type { addr | iface | number | flow } ] 386ac35ff17SAlexander V. Chernikov * [ algo algoname ] 387ac35ff17SAlexander V. Chernikov */ 388ac35ff17SAlexander V. Chernikov static void 389ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 390ac35ff17SAlexander V. Chernikov { 391ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 392ac35ff17SAlexander V. Chernikov int error, tcmd, val; 393*0cba2b28SAlexander V. Chernikov uint32_t fset, fclear; 394ac35ff17SAlexander V. Chernikov size_t sz; 395*0cba2b28SAlexander V. Chernikov char *e, *p; 396ac35ff17SAlexander V. Chernikov char tbuf[128]; 397ac35ff17SAlexander V. Chernikov 398ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 399ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 400ac35ff17SAlexander V. Chernikov 401ac35ff17SAlexander V. Chernikov while (ac > 0) { 402be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 403ac35ff17SAlexander V. Chernikov ac--; av++; 404ac35ff17SAlexander V. Chernikov 405ac35ff17SAlexander V. Chernikov switch (tcmd) { 4064c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 4074c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 4084c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 4094c0c07a5SAlexander V. Chernikov ac--; av++; 4104c0c07a5SAlexander V. Chernikov break; 411ac35ff17SAlexander V. Chernikov case TOK_TYPE: 412ac35ff17SAlexander V. Chernikov NEED1("table type required"); 413914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 414914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 415914bffb6SAlexander V. Chernikov *p++ = '\0'; 416ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 417914bffb6SAlexander V. Chernikov if (val == -1) { 418914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 419914bffb6SAlexander V. Chernikov ", "); 420914bffb6SAlexander V. Chernikov errx(EX_USAGE, 421914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 422ac35ff17SAlexander V. Chernikov *av, tbuf); 423914bffb6SAlexander V. Chernikov } 424914bffb6SAlexander V. Chernikov xi.type = val; 425914bffb6SAlexander V. Chernikov if (p != NULL) { 426914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 427914bffb6SAlexander V. Chernikov if (error != 0) 428914bffb6SAlexander V. Chernikov errx(EX_USAGE, 429914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 430914bffb6SAlexander V. Chernikov } 431914bffb6SAlexander V. Chernikov ac--; av++; 432ac35ff17SAlexander V. Chernikov break; 433ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 434ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 435*0cba2b28SAlexander V. Chernikov fset = fclear = 0; 436*0cba2b28SAlexander V. Chernikov val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear); 437ac35ff17SAlexander V. Chernikov if (val != -1) { 438*0cba2b28SAlexander V. Chernikov xi.vmask = fset; 439ac35ff17SAlexander V. Chernikov ac--; av++; 440ac35ff17SAlexander V. Chernikov break; 441ac35ff17SAlexander V. Chernikov } 442ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 443ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 444*0cba2b28SAlexander V. Chernikov e, tbuf); 445adf3b2b9SAlexander V. Chernikov break; 446ac35ff17SAlexander V. Chernikov case TOK_ALGO: 447ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 448ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 449ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 450ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 451ac35ff17SAlexander V. Chernikov ac--; av++; 452ac35ff17SAlexander V. Chernikov break; 4534f43138aSAlexander V. Chernikov case TOK_LOCK: 4544f43138aSAlexander V. Chernikov xi.flags |= IPFW_TGFLAGS_LOCKED; 4554f43138aSAlexander V. Chernikov break; 456ac35ff17SAlexander V. Chernikov } 457ac35ff17SAlexander V. Chernikov } 458ac35ff17SAlexander V. Chernikov 459fd0869d5SAlexander V. Chernikov /* Set some defaults to preserve compability */ 460fd0869d5SAlexander V. Chernikov if (xi.algoname[0] == '\0' && xi.type == 0) 461c21034b7SAlexander V. Chernikov xi.type = IPFW_TABLE_ADDR; 462*0cba2b28SAlexander V. Chernikov if (xi.vmask == 0) 463*0cba2b28SAlexander V. Chernikov xi.vmask = IPFW_VTYPE_LEGACY; 464fd0869d5SAlexander V. Chernikov 465ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 466ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 467f1220db8SAlexander V. Chernikov } 468f1220db8SAlexander V. Chernikov 469f1220db8SAlexander V. Chernikov /* 470ac35ff17SAlexander V. Chernikov * Creates new table 471ac35ff17SAlexander V. Chernikov * 472ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 473ac35ff17SAlexander V. Chernikov * 474f1220db8SAlexander V. Chernikov * Returns 0 on success. 475f1220db8SAlexander V. Chernikov */ 476f1220db8SAlexander V. Chernikov static int 477ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 478f1220db8SAlexander V. Chernikov { 479ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 480ac35ff17SAlexander V. Chernikov int error; 481f1220db8SAlexander V. Chernikov 482ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 483ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 484ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 485ac35ff17SAlexander V. Chernikov 486ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 487ac35ff17SAlexander V. Chernikov 488ac35ff17SAlexander V. Chernikov return (error); 489ac35ff17SAlexander V. Chernikov } 490ac35ff17SAlexander V. Chernikov 491ac35ff17SAlexander V. Chernikov /* 492adf3b2b9SAlexander V. Chernikov * Modifies existing table 493adf3b2b9SAlexander V. Chernikov * 494*0cba2b28SAlexander V. Chernikov * ipfw table NAME modify [ limit number ] 495adf3b2b9SAlexander V. Chernikov */ 496adf3b2b9SAlexander V. Chernikov static void 497adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[]) 498adf3b2b9SAlexander V. Chernikov { 499adf3b2b9SAlexander V. Chernikov ipfw_xtable_info xi; 500*0cba2b28SAlexander V. Chernikov int error, tcmd; 501adf3b2b9SAlexander V. Chernikov size_t sz; 502adf3b2b9SAlexander V. Chernikov char tbuf[128]; 503adf3b2b9SAlexander V. Chernikov 504adf3b2b9SAlexander V. Chernikov sz = sizeof(tbuf); 505adf3b2b9SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 506adf3b2b9SAlexander V. Chernikov 507adf3b2b9SAlexander V. Chernikov while (ac > 0) { 508be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 509adf3b2b9SAlexander V. Chernikov ac--; av++; 510adf3b2b9SAlexander V. Chernikov 511adf3b2b9SAlexander V. Chernikov switch (tcmd) { 512adf3b2b9SAlexander V. Chernikov case TOK_LIMIT: 513adf3b2b9SAlexander V. Chernikov NEED1("limit value required"); 514adf3b2b9SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 515adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LIMIT; 516adf3b2b9SAlexander V. Chernikov ac--; av++; 517adf3b2b9SAlexander V. Chernikov break; 518*0cba2b28SAlexander V. Chernikov default: 519*0cba2b28SAlexander V. Chernikov errx(EX_USAGE, "cmd is not supported for modificatiob"); 520adf3b2b9SAlexander V. Chernikov } 521adf3b2b9SAlexander V. Chernikov } 522adf3b2b9SAlexander V. Chernikov 523adf3b2b9SAlexander V. Chernikov if ((error = table_do_modify(oh, &xi)) != 0) 524adf3b2b9SAlexander V. Chernikov err(EX_OSERR, "Table modification failed"); 525adf3b2b9SAlexander V. Chernikov } 526adf3b2b9SAlexander V. Chernikov 527adf3b2b9SAlexander V. Chernikov /* 528adf3b2b9SAlexander V. Chernikov * Modifies existing table. 529adf3b2b9SAlexander V. Chernikov * 530adf3b2b9SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 531adf3b2b9SAlexander V. Chernikov * 532adf3b2b9SAlexander V. Chernikov * Returns 0 on success. 533adf3b2b9SAlexander V. Chernikov */ 534adf3b2b9SAlexander V. Chernikov static int 535adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 536adf3b2b9SAlexander V. Chernikov { 537adf3b2b9SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 538adf3b2b9SAlexander V. Chernikov int error; 539adf3b2b9SAlexander V. Chernikov 540adf3b2b9SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 541adf3b2b9SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 542adf3b2b9SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 543adf3b2b9SAlexander V. Chernikov 544adf3b2b9SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 545adf3b2b9SAlexander V. Chernikov 546adf3b2b9SAlexander V. Chernikov return (error); 547adf3b2b9SAlexander V. Chernikov } 5484f43138aSAlexander V. Chernikov 5494f43138aSAlexander V. Chernikov /* 5504f43138aSAlexander V. Chernikov * Locks or unlocks given table 5514f43138aSAlexander V. Chernikov */ 5524f43138aSAlexander V. Chernikov static void 5534f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock) 5544f43138aSAlexander V. Chernikov { 5554f43138aSAlexander V. Chernikov ipfw_xtable_info xi; 5564f43138aSAlexander V. Chernikov int error; 5574f43138aSAlexander V. Chernikov 5584f43138aSAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 5594f43138aSAlexander V. Chernikov 5604f43138aSAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LOCK; 5614f43138aSAlexander V. Chernikov xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; 5624f43138aSAlexander V. Chernikov 5634f43138aSAlexander V. Chernikov if ((error = table_do_modify(oh, &xi)) != 0) 5644f43138aSAlexander V. Chernikov err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); 5654f43138aSAlexander V. Chernikov } 5664f43138aSAlexander V. Chernikov 567adf3b2b9SAlexander V. Chernikov /* 568ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 569ac35ff17SAlexander V. Chernikov * Returns 0 on success. 570ac35ff17SAlexander V. Chernikov */ 571ac35ff17SAlexander V. Chernikov static int 572ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 573ac35ff17SAlexander V. Chernikov { 574ac35ff17SAlexander V. Chernikov 575ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 576f1220db8SAlexander V. Chernikov return (-1); 577f1220db8SAlexander V. Chernikov 578f1220db8SAlexander V. Chernikov return (0); 579f1220db8SAlexander V. Chernikov } 580f1220db8SAlexander V. Chernikov 581f1220db8SAlexander V. Chernikov /* 582ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 583f1220db8SAlexander V. Chernikov * Returns 0 on success. 584f1220db8SAlexander V. Chernikov */ 585f1220db8SAlexander V. Chernikov static int 586ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 587f1220db8SAlexander V. Chernikov { 588f1220db8SAlexander V. Chernikov 589ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 590f1220db8SAlexander V. Chernikov return (-1); 591f1220db8SAlexander V. Chernikov 592f1220db8SAlexander V. Chernikov return (0); 593f1220db8SAlexander V. Chernikov } 594f1220db8SAlexander V. Chernikov 59546d52008SAlexander V. Chernikov static int 59646d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 59746d52008SAlexander V. Chernikov { 59846d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 59946d52008SAlexander V. Chernikov int error; 60046d52008SAlexander V. Chernikov 60146d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 60246d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 60346d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 60446d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 60546d52008SAlexander V. Chernikov 60646d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 60746d52008SAlexander V. Chernikov 60846d52008SAlexander V. Chernikov return (error); 60946d52008SAlexander V. Chernikov } 61046d52008SAlexander V. Chernikov 61146d52008SAlexander V. Chernikov /* 61246d52008SAlexander V. Chernikov * Swaps given table with @second one. 61346d52008SAlexander V. Chernikov */ 61446d52008SAlexander V. Chernikov static int 61546d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 61646d52008SAlexander V. Chernikov { 61746d52008SAlexander V. Chernikov int error; 61846d52008SAlexander V. Chernikov 61946d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 62046d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 62146d52008SAlexander V. Chernikov 62246d52008SAlexander V. Chernikov error = table_do_swap(oh, second); 62346d52008SAlexander V. Chernikov 62446d52008SAlexander V. Chernikov switch (error) { 62546d52008SAlexander V. Chernikov case EINVAL: 62646d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 62746d52008SAlexander V. Chernikov case EFBIG: 62846d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 62946d52008SAlexander V. Chernikov } 63046d52008SAlexander V. Chernikov 63146d52008SAlexander V. Chernikov return (0); 63246d52008SAlexander V. Chernikov } 63346d52008SAlexander V. Chernikov 63446d52008SAlexander V. Chernikov 635f1220db8SAlexander V. Chernikov /* 636ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 637f1220db8SAlexander V. Chernikov * it inside @i. 638f1220db8SAlexander V. Chernikov * Returns 0 on success. 639f1220db8SAlexander V. Chernikov */ 640f1220db8SAlexander V. Chernikov static int 641ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 642f1220db8SAlexander V. Chernikov { 643f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 644ac35ff17SAlexander V. Chernikov int error; 645f1220db8SAlexander V. Chernikov size_t sz; 646f1220db8SAlexander V. Chernikov 647f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 648f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 649ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 650f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 651f1220db8SAlexander V. Chernikov 652ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 653ac35ff17SAlexander V. Chernikov return (error); 654f1220db8SAlexander V. Chernikov 655f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 656ac35ff17SAlexander V. Chernikov return (EINVAL); 657f1220db8SAlexander V. Chernikov 658f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 659f1220db8SAlexander V. Chernikov 660f1220db8SAlexander V. Chernikov return (0); 661f1220db8SAlexander V. Chernikov } 662f1220db8SAlexander V. Chernikov 6635f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 6645f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 6655f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 6665f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 6675f379342SAlexander V. Chernikov { NULL, 0 } 6685f379342SAlexander V. Chernikov }; 6695f379342SAlexander V. Chernikov 6705f379342SAlexander V. Chernikov struct ta_cldata { 6715f379342SAlexander V. Chernikov uint8_t taclass; 6725f379342SAlexander V. Chernikov uint8_t spare4; 6735f379342SAlexander V. Chernikov uint16_t itemsize; 6745f379342SAlexander V. Chernikov uint16_t itemsize6; 6755f379342SAlexander V. Chernikov uint32_t size; 6765f379342SAlexander V. Chernikov uint32_t count; 6775f379342SAlexander V. Chernikov }; 6785f379342SAlexander V. Chernikov 6795f379342SAlexander V. Chernikov /* 6805f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 6815f379342SAlexander V. Chernikov */ 6825f379342SAlexander V. Chernikov static void 6835f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 6845f379342SAlexander V. Chernikov const char *af, const char *taclass) 6855f379342SAlexander V. Chernikov { 6865f379342SAlexander V. Chernikov 6875f379342SAlexander V. Chernikov switch (d->taclass) { 6885f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 6895f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 6905f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 6915f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 6925f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 6935f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 6945f379342SAlexander V. Chernikov else 6955f379342SAlexander V. Chernikov printf(" size: %u items: %u " 6965f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 6975f379342SAlexander V. Chernikov d->size, d->count, 6985f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 6995f379342SAlexander V. Chernikov break; 7005f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 7015f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7025f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7035f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 7045f379342SAlexander V. Chernikov d->count, d->itemsize); 7055f379342SAlexander V. Chernikov else 7065f379342SAlexander V. Chernikov printf(" items: %u " 7075f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7085f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 7095f379342SAlexander V. Chernikov break; 7105f379342SAlexander V. Chernikov default: 7115f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 7125f379342SAlexander V. Chernikov } 7135f379342SAlexander V. Chernikov } 7145f379342SAlexander V. Chernikov 715*0cba2b28SAlexander V. Chernikov static void 716*0cba2b28SAlexander V. Chernikov table_print_valheader(char *buf, size_t bufsize, uint32_t vmask) 717*0cba2b28SAlexander V. Chernikov { 718*0cba2b28SAlexander V. Chernikov 719*0cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 720*0cba2b28SAlexander V. Chernikov snprintf(buf, bufsize, "legacy"); 721*0cba2b28SAlexander V. Chernikov return; 722*0cba2b28SAlexander V. Chernikov } 723*0cba2b28SAlexander V. Chernikov 724*0cba2b28SAlexander V. Chernikov print_flags_buffer(buf, bufsize, tablevaltypes, vmask); 725*0cba2b28SAlexander V. Chernikov } 726*0cba2b28SAlexander V. Chernikov 727f1220db8SAlexander V. Chernikov /* 728f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 729f1220db8SAlexander V. Chernikov */ 730f1220db8SAlexander V. Chernikov static int 731f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 732f1220db8SAlexander V. Chernikov { 733*0cba2b28SAlexander V. Chernikov const char *vtype; 7345f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 7355f379342SAlexander V. Chernikov int afdata, afitem; 7365f379342SAlexander V. Chernikov struct ta_cldata d; 737adf3b2b9SAlexander V. Chernikov char ttype[64], tvtype[64]; 738f1220db8SAlexander V. Chernikov 739914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 740*0cba2b28SAlexander V. Chernikov table_print_valheader(tvtype, sizeof(tvtype), i->vmask); 741ac35ff17SAlexander V. Chernikov 742914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 7434f43138aSAlexander V. Chernikov if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) 7444f43138aSAlexander V. Chernikov printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); 7454f43138aSAlexander V. Chernikov else 746914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 747*0cba2b28SAlexander V. Chernikov printf(" references: %u, valtype: %s\n", i->refcnt, tvtype); 7489d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 749f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 7504c0c07a5SAlexander V. Chernikov if (i->limit > 0) 7514c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 752f1220db8SAlexander V. Chernikov 753358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 754358b9d09SAlexander V. Chernikov if (arg == NULL) 755358b9d09SAlexander V. Chernikov return (0); 756358b9d09SAlexander V. Chernikov 7575f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 7585f379342SAlexander V. Chernikov return (0); 7595f379342SAlexander V. Chernikov tainfo = &i->ta_info; 7605f379342SAlexander V. Chernikov 7615f379342SAlexander V. Chernikov afdata = 0; 7625f379342SAlexander V. Chernikov afitem = 0; 7635f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 7645f379342SAlexander V. Chernikov afdata = 1; 7655f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 7665f379342SAlexander V. Chernikov afitem = 1; 7675f379342SAlexander V. Chernikov 7685f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7695f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 7705f379342SAlexander V. Chernikov d.size = tainfo->size4; 7715f379342SAlexander V. Chernikov d.count = tainfo->count4; 7725f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 7735f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 7745f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 7755f379342SAlexander V. Chernikov else 7765f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7775f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7785f379342SAlexander V. Chernikov vtype = "unknown"; 7795f379342SAlexander V. Chernikov 7805f379342SAlexander V. Chernikov if (afdata == 0) { 7815f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 7825f379342SAlexander V. Chernikov } else { 7835f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 7845f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7855f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 7865f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7875f379342SAlexander V. Chernikov vtype = "unknown"; 7885f379342SAlexander V. Chernikov d.size = tainfo->size6; 7895f379342SAlexander V. Chernikov d.count = tainfo->count6; 7905f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 7915f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7925f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 7935f379342SAlexander V. Chernikov } 7945f379342SAlexander V. Chernikov 795f1220db8SAlexander V. Chernikov return (0); 796f1220db8SAlexander V. Chernikov } 797f1220db8SAlexander V. Chernikov 798f1220db8SAlexander V. Chernikov 799f1220db8SAlexander V. Chernikov /* 800f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 801f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 802f1220db8SAlexander V. Chernikov */ 803f1220db8SAlexander V. Chernikov 804f1220db8SAlexander V. Chernikov static int 805f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 806f1220db8SAlexander V. Chernikov { 807f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 80881d3153dSAlexander V. Chernikov int error; 809f1220db8SAlexander V. Chernikov 810720ee730SAlexander V. Chernikov if ((error = table_do_get_list(i, &oh)) != 0) { 81181d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 81281d3153dSAlexander V. Chernikov return (error); 81381d3153dSAlexander V. Chernikov } 81481d3153dSAlexander V. Chernikov 815f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 816f1220db8SAlexander V. Chernikov 817f1220db8SAlexander V. Chernikov free(oh); 818f1220db8SAlexander V. Chernikov return (0); 819f1220db8SAlexander V. Chernikov } 820f1220db8SAlexander V. Chernikov 821f1220db8SAlexander V. Chernikov static int 822f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 823f1220db8SAlexander V. Chernikov { 824ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 825f1220db8SAlexander V. Chernikov 826ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 827ac35ff17SAlexander V. Chernikov 828ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 829ac35ff17SAlexander V. Chernikov 830ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 831f1220db8SAlexander V. Chernikov } 832f1220db8SAlexander V. Chernikov 833ac35ff17SAlexander V. Chernikov static int 834ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 8353a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent, int count, int atomic) 836ac35ff17SAlexander V. Chernikov { 837db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 8383a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent_base; 8393a845e10SAlexander V. Chernikov caddr_t pbuf; 840db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 8413a845e10SAlexander V. Chernikov int error, i; 8423a845e10SAlexander V. Chernikov size_t sz; 843ac35ff17SAlexander V. Chernikov 8443a845e10SAlexander V. Chernikov sz = sizeof(*ctlv) + sizeof(*tent) * count; 8453a845e10SAlexander V. Chernikov if (count == 1) { 846ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 8473a845e10SAlexander V. Chernikov pbuf = xbuf; 8483a845e10SAlexander V. Chernikov } else { 8493a845e10SAlexander V. Chernikov if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) 8503a845e10SAlexander V. Chernikov return (ENOMEM); 8513a845e10SAlexander V. Chernikov } 8523a845e10SAlexander V. Chernikov 8533a845e10SAlexander V. Chernikov memcpy(pbuf, oh, sizeof(*oh)); 8543a845e10SAlexander V. Chernikov oh = (ipfw_obj_header *)pbuf; 855ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 856ac35ff17SAlexander V. Chernikov 857db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 8583a845e10SAlexander V. Chernikov ctlv->count = count; 8593a845e10SAlexander V. Chernikov ctlv->head.length = sz; 8603a845e10SAlexander V. Chernikov if (atomic != 0) 8613a845e10SAlexander V. Chernikov ctlv->flags |= IPFW_CTF_ATOMIC; 862db785d31SAlexander V. Chernikov 8633a845e10SAlexander V. Chernikov tent_base = tent; 8643a845e10SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent) * count); 865db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 8663a845e10SAlexander V. Chernikov for (i = 0; i < count; i++, tent++) { 867ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 8683a845e10SAlexander V. Chernikov tent->idx = oh->idx; 8693a845e10SAlexander V. Chernikov } 870ac35ff17SAlexander V. Chernikov 8713a845e10SAlexander V. Chernikov sz += sizeof(*oh); 8723a845e10SAlexander V. Chernikov error = do_get3(cmd, &oh->opheader, &sz); 8733a845e10SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 8743a845e10SAlexander V. Chernikov /* Copy result back to provided buffer */ 8753a845e10SAlexander V. Chernikov memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); 8763a845e10SAlexander V. Chernikov 8773a845e10SAlexander V. Chernikov if (pbuf != xbuf) 8783a845e10SAlexander V. Chernikov free(pbuf); 879ac35ff17SAlexander V. Chernikov 880ac35ff17SAlexander V. Chernikov return (error); 881ac35ff17SAlexander V. Chernikov } 882ac35ff17SAlexander V. Chernikov 883ac35ff17SAlexander V. Chernikov static void 8843a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, 8853a845e10SAlexander V. Chernikov int quiet, int update, int atomic) 886ac35ff17SAlexander V. Chernikov { 8873a845e10SAlexander V. Chernikov ipfw_obj_tentry *ptent, tent, *tent_buf; 88881d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 889*0cba2b28SAlexander V. Chernikov uint8_t type; 890*0cba2b28SAlexander V. Chernikov uint32_t vmask; 8913a845e10SAlexander V. Chernikov int cmd, count, error, i, ignored; 8923a845e10SAlexander V. Chernikov char *texterr, *etxt, *px; 893ac35ff17SAlexander V. Chernikov 894ac35ff17SAlexander V. Chernikov if (ac == 0) 895ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 896ac35ff17SAlexander V. Chernikov 897ac35ff17SAlexander V. Chernikov if (add != 0) { 898ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 8994c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 900ac35ff17SAlexander V. Chernikov } else { 901ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 9024c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 903ac35ff17SAlexander V. Chernikov } 904ac35ff17SAlexander V. Chernikov 9053a845e10SAlexander V. Chernikov /* 9063a845e10SAlexander V. Chernikov * Calculate number of entries: 9073a845e10SAlexander V. Chernikov * Assume [key val] x N for add 9083a845e10SAlexander V. Chernikov * and 9093a845e10SAlexander V. Chernikov * key x N for delete 9103a845e10SAlexander V. Chernikov */ 9113a845e10SAlexander V. Chernikov count = (add != 0) ? ac / 2 + 1 : ac; 9123a845e10SAlexander V. Chernikov 9133a845e10SAlexander V. Chernikov if (count <= 1) { 9143a845e10SAlexander V. Chernikov /* Adding single entry with/without value */ 9153a845e10SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 9163a845e10SAlexander V. Chernikov tent_buf = &tent; 9173a845e10SAlexander V. Chernikov } else { 9183a845e10SAlexander V. Chernikov 9193a845e10SAlexander V. Chernikov if ((tent_buf = calloc(count, sizeof(tent))) == NULL) 9203a845e10SAlexander V. Chernikov errx(EX_OSERR, 9213a845e10SAlexander V. Chernikov "Unable to allocate memory for all entries"); 9223a845e10SAlexander V. Chernikov } 9233a845e10SAlexander V. Chernikov ptent = tent_buf; 9243a845e10SAlexander V. Chernikov 9253a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 9263a845e10SAlexander V. Chernikov count = 0; 9273a845e10SAlexander V. Chernikov while (ac > 0) { 928*0cba2b28SAlexander V. Chernikov tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi); 9293a845e10SAlexander V. Chernikov 9303a845e10SAlexander V. Chernikov /* 9313a845e10SAlexander V. Chernikov * compability layer: auto-create table if not exists 9323a845e10SAlexander V. Chernikov */ 9333a845e10SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 9343a845e10SAlexander V. Chernikov xi.type = type; 935*0cba2b28SAlexander V. Chernikov xi.vmask = vmask; 9363a845e10SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, 9373a845e10SAlexander V. Chernikov sizeof(xi.tablename)); 9383a845e10SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info " 9393a845e10SAlexander V. Chernikov "non-existent table %s. (auto-created)\n", 9403a845e10SAlexander V. Chernikov xi.tablename); 9413a845e10SAlexander V. Chernikov table_do_create(oh, &xi); 9423a845e10SAlexander V. Chernikov } 9433a845e10SAlexander V. Chernikov 9443a845e10SAlexander V. Chernikov oh->ntlv.type = type; 9453a845e10SAlexander V. Chernikov ac--; av++; 9463a845e10SAlexander V. Chernikov 9473a845e10SAlexander V. Chernikov if (add != 0 && ac > 0) { 948*0cba2b28SAlexander V. Chernikov tentry_fill_value(oh, ptent, *av, type, vmask); 9493a845e10SAlexander V. Chernikov ac--; av++; 9503a845e10SAlexander V. Chernikov } 9513a845e10SAlexander V. Chernikov 9523a845e10SAlexander V. Chernikov if (update != 0) 9533a845e10SAlexander V. Chernikov ptent->head.flags |= IPFW_TF_UPDATE; 9543a845e10SAlexander V. Chernikov 9553a845e10SAlexander V. Chernikov count++; 9563a845e10SAlexander V. Chernikov ptent++; 9573a845e10SAlexander V. Chernikov } 9583a845e10SAlexander V. Chernikov 9593a845e10SAlexander V. Chernikov error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 9603a845e10SAlexander V. Chernikov 961*0cba2b28SAlexander V. Chernikov quiet = 0; 962*0cba2b28SAlexander V. Chernikov 9633a845e10SAlexander V. Chernikov /* 9643a845e10SAlexander V. Chernikov * Compatibility stuff: do not yell on duplicate keys or 9653a845e10SAlexander V. Chernikov * failed deletions. 9663a845e10SAlexander V. Chernikov */ 9673a845e10SAlexander V. Chernikov if (error == 0 || (error == EEXIST && add != 0) || 9683a845e10SAlexander V. Chernikov (error == ENOENT && add == 0)) { 9693a845e10SAlexander V. Chernikov if (quiet != 0) { 9703a845e10SAlexander V. Chernikov if (tent_buf != &tent) 9713a845e10SAlexander V. Chernikov free(tent_buf); 9723a845e10SAlexander V. Chernikov return; 9733a845e10SAlexander V. Chernikov } 9743a845e10SAlexander V. Chernikov } 9753a845e10SAlexander V. Chernikov 9763a845e10SAlexander V. Chernikov /* Report results back */ 9773a845e10SAlexander V. Chernikov ptent = tent_buf; 9783a845e10SAlexander V. Chernikov for (i = 0; i < count; ptent++, i++) { 9793a845e10SAlexander V. Chernikov ignored = 0; 9803a845e10SAlexander V. Chernikov switch (ptent->result) { 9813a845e10SAlexander V. Chernikov case IPFW_TR_ADDED: 9823a845e10SAlexander V. Chernikov px = "added"; 9833a845e10SAlexander V. Chernikov break; 9843a845e10SAlexander V. Chernikov case IPFW_TR_DELETED: 9853a845e10SAlexander V. Chernikov px = "deleted"; 9863a845e10SAlexander V. Chernikov break; 9873a845e10SAlexander V. Chernikov case IPFW_TR_UPDATED: 9883a845e10SAlexander V. Chernikov px = "updated"; 9893a845e10SAlexander V. Chernikov break; 9903a845e10SAlexander V. Chernikov case IPFW_TR_LIMIT: 9913a845e10SAlexander V. Chernikov px = "limit"; 9923a845e10SAlexander V. Chernikov ignored = 1; 9933a845e10SAlexander V. Chernikov break; 9943a845e10SAlexander V. Chernikov case IPFW_TR_ERROR: 9953a845e10SAlexander V. Chernikov px = "error"; 9963a845e10SAlexander V. Chernikov ignored = 1; 9973a845e10SAlexander V. Chernikov break; 9983a845e10SAlexander V. Chernikov case IPFW_TR_NOTFOUND: 9993a845e10SAlexander V. Chernikov px = "notfound"; 10003a845e10SAlexander V. Chernikov ignored = 1; 10013a845e10SAlexander V. Chernikov break; 10023a845e10SAlexander V. Chernikov case IPFW_TR_EXISTS: 10033a845e10SAlexander V. Chernikov px = "exists"; 10043a845e10SAlexander V. Chernikov ignored = 1; 10053a845e10SAlexander V. Chernikov break; 10063a845e10SAlexander V. Chernikov case IPFW_TR_IGNORED: 10073a845e10SAlexander V. Chernikov px = "ignored"; 10083a845e10SAlexander V. Chernikov ignored = 1; 10093a845e10SAlexander V. Chernikov break; 10103a845e10SAlexander V. Chernikov default: 10113a845e10SAlexander V. Chernikov px = "unknown"; 10123a845e10SAlexander V. Chernikov ignored = 1; 10133a845e10SAlexander V. Chernikov } 10143a845e10SAlexander V. Chernikov 10153a845e10SAlexander V. Chernikov if (error != 0 && atomic != 0 && ignored == 0) 10163a845e10SAlexander V. Chernikov printf("%s(reverted): ", px); 10173a845e10SAlexander V. Chernikov else 10183a845e10SAlexander V. Chernikov printf("%s: ", px); 10193a845e10SAlexander V. Chernikov 10203a845e10SAlexander V. Chernikov table_show_entry(&xi, ptent); 10213a845e10SAlexander V. Chernikov } 10223a845e10SAlexander V. Chernikov 10233a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10243a845e10SAlexander V. Chernikov free(tent_buf); 10253a845e10SAlexander V. Chernikov 10263a845e10SAlexander V. Chernikov if (error == 0) 10274c0c07a5SAlexander V. Chernikov return; 10284c0c07a5SAlexander V. Chernikov 10294c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 10304c0c07a5SAlexander V. Chernikov switch (error) { 10314c0c07a5SAlexander V. Chernikov case EEXIST: 10324c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 10334c0c07a5SAlexander V. Chernikov break; 10344c0c07a5SAlexander V. Chernikov case EFBIG: 10354c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 10364c0c07a5SAlexander V. Chernikov break; 10374c0c07a5SAlexander V. Chernikov case ESRCH: 10384c0c07a5SAlexander V. Chernikov etxt = "table not found"; 10394c0c07a5SAlexander V. Chernikov break; 10404c0c07a5SAlexander V. Chernikov case ENOENT: 10414c0c07a5SAlexander V. Chernikov etxt = "record not found"; 10424c0c07a5SAlexander V. Chernikov break; 10434f43138aSAlexander V. Chernikov case EACCES: 10444f43138aSAlexander V. Chernikov etxt = "table is locked"; 10454f43138aSAlexander V. Chernikov break; 10464c0c07a5SAlexander V. Chernikov default: 10474c0c07a5SAlexander V. Chernikov etxt = strerror(error); 10484c0c07a5SAlexander V. Chernikov } 10494c0c07a5SAlexander V. Chernikov 10504c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 1051ac35ff17SAlexander V. Chernikov } 1052ac35ff17SAlexander V. Chernikov 105381d3153dSAlexander V. Chernikov static int 105481d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 105581d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 105681d3153dSAlexander V. Chernikov { 105781d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 105881d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 1059*0cba2b28SAlexander V. Chernikov uint8_t type; 1060*0cba2b28SAlexander V. Chernikov uint32_t vmask; 106181d3153dSAlexander V. Chernikov int error; 106281d3153dSAlexander V. Chernikov size_t sz; 106381d3153dSAlexander V. Chernikov 106481d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 106581d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 106681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 106781d3153dSAlexander V. Chernikov 106881d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 106981d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 107081d3153dSAlexander V. Chernikov tent->idx = 1; 107181d3153dSAlexander V. Chernikov 1072*0cba2b28SAlexander V. Chernikov tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); 107381d3153dSAlexander V. Chernikov oh->ntlv.type = type; 107481d3153dSAlexander V. Chernikov 107581d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 107681d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 107781d3153dSAlexander V. Chernikov return (error); 107881d3153dSAlexander V. Chernikov 107981d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 108081d3153dSAlexander V. Chernikov return (EINVAL); 108181d3153dSAlexander V. Chernikov 108281d3153dSAlexander V. Chernikov *xtent = *tent; 108381d3153dSAlexander V. Chernikov 108481d3153dSAlexander V. Chernikov return (0); 108581d3153dSAlexander V. Chernikov } 108681d3153dSAlexander V. Chernikov 108781d3153dSAlexander V. Chernikov static void 108881d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 108981d3153dSAlexander V. Chernikov { 109081d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 109181d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 1092914bffb6SAlexander V. Chernikov char key[64]; 109381d3153dSAlexander V. Chernikov int error; 109481d3153dSAlexander V. Chernikov 109581d3153dSAlexander V. Chernikov if (ac == 0) 109681d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 109781d3153dSAlexander V. Chernikov 1098914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 1099914bffb6SAlexander V. Chernikov 11003a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 1101914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 110281d3153dSAlexander V. Chernikov 110381d3153dSAlexander V. Chernikov switch (error) { 110481d3153dSAlexander V. Chernikov case 0: 110581d3153dSAlexander V. Chernikov break; 110681d3153dSAlexander V. Chernikov case ESRCH: 110781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 110881d3153dSAlexander V. Chernikov case ENOENT: 110981d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 111081d3153dSAlexander V. Chernikov case ENOTSUP: 111181d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 111281d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 111381d3153dSAlexander V. Chernikov default: 111481d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 111581d3153dSAlexander V. Chernikov } 111681d3153dSAlexander V. Chernikov 111781d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 111881d3153dSAlexander V. Chernikov } 1119ac35ff17SAlexander V. Chernikov 1120ac35ff17SAlexander V. Chernikov static void 1121914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1122914bffb6SAlexander V. Chernikov uint8_t tflags) 1123ac35ff17SAlexander V. Chernikov { 1124914bffb6SAlexander V. Chernikov char *p, *pp; 1125ac35ff17SAlexander V. Chernikov int mask, af; 1126914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 1127914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 1128ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 1129914bffb6SAlexander V. Chernikov uint16_t port; 1130914bffb6SAlexander V. Chernikov struct protoent *pent; 1131914bffb6SAlexander V. Chernikov struct servent *sent; 1132ac35ff17SAlexander V. Chernikov int masklen; 1133ac35ff17SAlexander V. Chernikov 1134ac35ff17SAlexander V. Chernikov masklen = 0; 1135ac35ff17SAlexander V. Chernikov af = 0; 1136ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 1137ac35ff17SAlexander V. Chernikov 1138ac35ff17SAlexander V. Chernikov switch (type) { 1139c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1140ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 1141ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 1142ac35ff17SAlexander V. Chernikov *p = '\0'; 1143ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 1144ac35ff17SAlexander V. Chernikov } 1145ac35ff17SAlexander V. Chernikov 1146ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 1147ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 1148ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 1149ac35ff17SAlexander V. Chernikov p + 1); 1150ac35ff17SAlexander V. Chernikov 1151ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 1152ac35ff17SAlexander V. Chernikov af = AF_INET; 1153ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 1154ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 1155ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 1156ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 1157ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 1158ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 1159ac35ff17SAlexander V. Chernikov p + 1); 1160ac35ff17SAlexander V. Chernikov 1161ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 1162ac35ff17SAlexander V. Chernikov af = AF_INET6; 1163ac35ff17SAlexander V. Chernikov } else { 1164ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 1165ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1166ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1167ac35ff17SAlexander V. Chernikov 1168ac35ff17SAlexander V. Chernikov masklen = 32; 1169c21034b7SAlexander V. Chernikov type = IPFW_TABLE_ADDR; 1170ac35ff17SAlexander V. Chernikov af = AF_INET; 1171ac35ff17SAlexander V. Chernikov } 1172ac35ff17SAlexander V. Chernikov break; 1173ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1174ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 1175ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1176ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 1177ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 1178ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 1179ac35ff17SAlexander V. Chernikov break; 1180b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1181ac35ff17SAlexander V. Chernikov /* Port or any other key */ 1182ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 1183ac35ff17SAlexander V. Chernikov if (*p != '\0') 1184ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 1185ac35ff17SAlexander V. Chernikov 1186ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 1187ac35ff17SAlexander V. Chernikov *pkey = key; 1188ac35ff17SAlexander V. Chernikov masklen = 32; 1189ac35ff17SAlexander V. Chernikov break; 1190914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1191914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1192914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 1193914bffb6SAlexander V. Chernikov af = 0; 1194914bffb6SAlexander V. Chernikov 1195914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6> */ 1196914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1197914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1198914bffb6SAlexander V. Chernikov *p++ = '\0'; 1199914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1200914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1201914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1202914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1203914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1204914bffb6SAlexander V. Chernikov af = AF_INET; 1205914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 1206914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1207914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1208914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1209914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1210914bffb6SAlexander V. Chernikov af = AF_INET6; 1211914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 1212914bffb6SAlexander V. Chernikov } 1213914bffb6SAlexander V. Chernikov 1214914bffb6SAlexander V. Chernikov arg = p; 1215914bffb6SAlexander V. Chernikov } 1216914bffb6SAlexander V. Chernikov 1217914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 1218914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 121935df97d0SAlexander V. Chernikov if (arg == NULL) 122035df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: proto missing"); 1221914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1222914bffb6SAlexander V. Chernikov *p++ = '\0'; 1223914bffb6SAlexander V. Chernikov 1224914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 1225914bffb6SAlexander V. Chernikov if (*pp != '\0') { 1226914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 1227914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 1228914bffb6SAlexander V. Chernikov arg); 1229914bffb6SAlexander V. Chernikov else 1230914bffb6SAlexander V. Chernikov key = pent->p_proto; 1231914bffb6SAlexander V. Chernikov } 1232914bffb6SAlexander V. Chernikov 1233914bffb6SAlexander V. Chernikov if (key > 255) 1234914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 1235914bffb6SAlexander V. Chernikov 1236914bffb6SAlexander V. Chernikov tfe->proto = key; 1237914bffb6SAlexander V. Chernikov 1238914bffb6SAlexander V. Chernikov arg = p; 1239914bffb6SAlexander V. Chernikov } 1240914bffb6SAlexander V. Chernikov 1241914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1242914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 124335df97d0SAlexander V. Chernikov if (arg == NULL) 124435df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: src port missing"); 1245914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1246914bffb6SAlexander V. Chernikov *p++ = '\0'; 1247914bffb6SAlexander V. Chernikov 1248914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1249914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1250914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1251914bffb6SAlexander V. Chernikov arg); 1252914bffb6SAlexander V. Chernikov else 1253914bffb6SAlexander V. Chernikov key = sent->s_port; 1254914bffb6SAlexander V. Chernikov } 1255914bffb6SAlexander V. Chernikov 1256914bffb6SAlexander V. Chernikov tfe->sport = port; 1257914bffb6SAlexander V. Chernikov 1258914bffb6SAlexander V. Chernikov arg = p; 1259914bffb6SAlexander V. Chernikov } 1260914bffb6SAlexander V. Chernikov 1261914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1262914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 126335df97d0SAlexander V. Chernikov if (arg == NULL) 126435df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst ip missing"); 1265914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1266914bffb6SAlexander V. Chernikov *p++ = '\0'; 1267914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1268914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1269914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1270914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1271914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1272914bffb6SAlexander V. Chernikov af = AF_INET; 1273914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 1274914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1275914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1276914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1277914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1278914bffb6SAlexander V. Chernikov af = AF_INET6; 1279914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1280914bffb6SAlexander V. Chernikov } 1281914bffb6SAlexander V. Chernikov 1282914bffb6SAlexander V. Chernikov arg = p; 1283914bffb6SAlexander V. Chernikov } 1284914bffb6SAlexander V. Chernikov 1285914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1286914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 128735df97d0SAlexander V. Chernikov if (arg == NULL) 128835df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst port missing"); 1289914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1290914bffb6SAlexander V. Chernikov *p++ = '\0'; 1291914bffb6SAlexander V. Chernikov 1292914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1293914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1294914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1295914bffb6SAlexander V. Chernikov arg); 1296914bffb6SAlexander V. Chernikov else 1297914bffb6SAlexander V. Chernikov key = sent->s_port; 1298914bffb6SAlexander V. Chernikov } 1299914bffb6SAlexander V. Chernikov 1300914bffb6SAlexander V. Chernikov tfe->dport = port; 1301914bffb6SAlexander V. Chernikov 1302914bffb6SAlexander V. Chernikov arg = p; 1303914bffb6SAlexander V. Chernikov } 1304914bffb6SAlexander V. Chernikov 1305914bffb6SAlexander V. Chernikov tfe->af = af; 1306914bffb6SAlexander V. Chernikov 1307914bffb6SAlexander V. Chernikov break; 1308914bffb6SAlexander V. Chernikov 1309ac35ff17SAlexander V. Chernikov default: 1310ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1311ac35ff17SAlexander V. Chernikov } 1312ac35ff17SAlexander V. Chernikov 1313ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1314ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1315ac35ff17SAlexander V. Chernikov } 1316ac35ff17SAlexander V. Chernikov 1317ac35ff17SAlexander V. Chernikov static void 1318ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 1319*0cba2b28SAlexander V. Chernikov int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) 1320ac35ff17SAlexander V. Chernikov { 1321*0cba2b28SAlexander V. Chernikov uint8_t type, tflags; 1322*0cba2b28SAlexander V. Chernikov uint32_t vmask; 1323ac35ff17SAlexander V. Chernikov int error; 1324db785d31SAlexander V. Chernikov char *del; 1325ac35ff17SAlexander V. Chernikov 1326ac35ff17SAlexander V. Chernikov type = 0; 1327914bffb6SAlexander V. Chernikov tflags = 0; 1328*0cba2b28SAlexander V. Chernikov vmask = 0; 1329ac35ff17SAlexander V. Chernikov 13303a845e10SAlexander V. Chernikov if (xi->tablename[0] == '\0') 133181d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 13323a845e10SAlexander V. Chernikov else 13333a845e10SAlexander V. Chernikov error = 0; 133481d3153dSAlexander V. Chernikov 133581d3153dSAlexander V. Chernikov if (error == 0) { 133681d3153dSAlexander V. Chernikov /* Table found. */ 133781d3153dSAlexander V. Chernikov type = xi->type; 1338914bffb6SAlexander V. Chernikov tflags = xi->tflags; 1339*0cba2b28SAlexander V. Chernikov vmask = xi->vmask; 134081d3153dSAlexander V. Chernikov } else { 134181d3153dSAlexander V. Chernikov if (error != ESRCH) 134281d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 134381d3153dSAlexander V. Chernikov oh->ntlv.name); 134435df97d0SAlexander V. Chernikov if (add == 0) 134535df97d0SAlexander V. Chernikov errx(EX_DATAERR, "Table %s does not exist", 134635df97d0SAlexander V. Chernikov oh->ntlv.name); 1347ac35ff17SAlexander V. Chernikov /* 134881d3153dSAlexander V. Chernikov * Table does not exist. 1349c21034b7SAlexander V. Chernikov * Compability layer: try to interpret data as ADDR 135081d3153dSAlexander V. Chernikov * before failing. 1351ac35ff17SAlexander V. Chernikov */ 1352db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 1353db785d31SAlexander V. Chernikov *del = '\0'; 1354ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 1355ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 1356ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 1357c21034b7SAlexander V. Chernikov type = IPFW_TABLE_ADDR; 1358*0cba2b28SAlexander V. Chernikov vmask = IPFW_VTYPE_LEGACY; 135981d3153dSAlexander V. Chernikov } else { 136081d3153dSAlexander V. Chernikov /* Inknown key */ 136181d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1362db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 136381d3153dSAlexander V. Chernikov } 1364db785d31SAlexander V. Chernikov if (del != NULL) 1365db785d31SAlexander V. Chernikov *del = '/'; 1366ac35ff17SAlexander V. Chernikov } 1367ac35ff17SAlexander V. Chernikov 1368914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1369ac35ff17SAlexander V. Chernikov 1370ac35ff17SAlexander V. Chernikov *ptype = type; 1371*0cba2b28SAlexander V. Chernikov *pvmask = vmask; 1372*0cba2b28SAlexander V. Chernikov } 1373*0cba2b28SAlexander V. Chernikov 1374*0cba2b28SAlexander V. Chernikov static void 1375*0cba2b28SAlexander V. Chernikov set_legacy_value(uint32_t val, ipfw_table_value *v) 1376*0cba2b28SAlexander V. Chernikov { 1377*0cba2b28SAlexander V. Chernikov v->tag = val; 1378*0cba2b28SAlexander V. Chernikov v->pipe = val; 1379*0cba2b28SAlexander V. Chernikov v->divert = val; 1380*0cba2b28SAlexander V. Chernikov v->skipto = val; 1381*0cba2b28SAlexander V. Chernikov v->netgraph = val; 1382*0cba2b28SAlexander V. Chernikov v->fib = val; 1383*0cba2b28SAlexander V. Chernikov v->nat = val; 1384*0cba2b28SAlexander V. Chernikov v->nh4 = val; 1385*0cba2b28SAlexander V. Chernikov v->dscp = (uint8_t)val; 1386*0cba2b28SAlexander V. Chernikov v->limit = val; 1387ac35ff17SAlexander V. Chernikov } 1388ac35ff17SAlexander V. Chernikov 1389ac35ff17SAlexander V. Chernikov static void 1390ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1391*0cba2b28SAlexander V. Chernikov uint8_t type, uint32_t vmask) 1392ac35ff17SAlexander V. Chernikov { 1393*0cba2b28SAlexander V. Chernikov uint32_t a4, flag, val, vm; 1394*0cba2b28SAlexander V. Chernikov ipfw_table_value *v; 1395*0cba2b28SAlexander V. Chernikov uint32_t i; 1396*0cba2b28SAlexander V. Chernikov char *comma, *e, *etype, *n, *p; 1397ac35ff17SAlexander V. Chernikov 1398*0cba2b28SAlexander V. Chernikov v = &tent->v.value; 1399*0cba2b28SAlexander V. Chernikov vm = vmask; 1400*0cba2b28SAlexander V. Chernikov 1401*0cba2b28SAlexander V. Chernikov /* Compat layer: keep old behavior for legacy value types */ 1402*0cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 1403adf3b2b9SAlexander V. Chernikov /* Try to interpret as number first */ 1404*0cba2b28SAlexander V. Chernikov val = strtoul(arg, &p, 0); 1405*0cba2b28SAlexander V. Chernikov if (*p == '\0') { 1406*0cba2b28SAlexander V. Chernikov set_legacy_value(val, v); 1407adf3b2b9SAlexander V. Chernikov return; 1408*0cba2b28SAlexander V. Chernikov } 1409adf3b2b9SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &val) == 1) { 1410*0cba2b28SAlexander V. Chernikov set_legacy_value(ntohl(val), v); 1411adf3b2b9SAlexander V. Chernikov return; 1412adf3b2b9SAlexander V. Chernikov } 1413adf3b2b9SAlexander V. Chernikov /* Try hostname */ 1414*0cba2b28SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&val) == 0) { 1415*0cba2b28SAlexander V. Chernikov set_legacy_value(val, v); 1416adf3b2b9SAlexander V. Chernikov return; 1417*0cba2b28SAlexander V. Chernikov } 1418adf3b2b9SAlexander V. Chernikov errx(EX_OSERR, "Unable to parse value %s", arg); 1419*0cba2b28SAlexander V. Chernikov } 1420*0cba2b28SAlexander V. Chernikov 1421*0cba2b28SAlexander V. Chernikov /* 1422*0cba2b28SAlexander V. Chernikov * Shorthands: handle single value if vmask consists 1423*0cba2b28SAlexander V. Chernikov * of numbers only. e.g.: 1424*0cba2b28SAlexander V. Chernikov * vmask = "fib,skipto" -> treat input "1" as "1,1" 1425*0cba2b28SAlexander V. Chernikov */ 1426*0cba2b28SAlexander V. Chernikov 1427*0cba2b28SAlexander V. Chernikov n = arg; 1428*0cba2b28SAlexander V. Chernikov etype = NULL; 1429*0cba2b28SAlexander V. Chernikov for (i = 1; i < (1 << 31); i *= 2) { 1430*0cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 1431*0cba2b28SAlexander V. Chernikov continue; 1432*0cba2b28SAlexander V. Chernikov vmask &= ~flag; 1433*0cba2b28SAlexander V. Chernikov 1434*0cba2b28SAlexander V. Chernikov if ((comma = strchr(n, ',')) != NULL) 1435*0cba2b28SAlexander V. Chernikov *comma = '\0'; 1436*0cba2b28SAlexander V. Chernikov 1437*0cba2b28SAlexander V. Chernikov switch (flag) { 1438*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 1439*0cba2b28SAlexander V. Chernikov v->tag = strtol(n, &e, 10); 1440*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1441*0cba2b28SAlexander V. Chernikov etype = "tag"; 1442ac35ff17SAlexander V. Chernikov break; 1443*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 1444*0cba2b28SAlexander V. Chernikov v->pipe = strtol(n, &e, 10); 1445*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1446*0cba2b28SAlexander V. Chernikov etype = "pipe"; 1447ac35ff17SAlexander V. Chernikov break; 1448*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 1449*0cba2b28SAlexander V. Chernikov v->divert = strtol(n, &e, 10); 1450*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1451*0cba2b28SAlexander V. Chernikov etype = "divert"; 1452*0cba2b28SAlexander V. Chernikov break; 1453*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 1454*0cba2b28SAlexander V. Chernikov v->skipto = strtol(n, &e, 10); 1455*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1456*0cba2b28SAlexander V. Chernikov etype = "skipto"; 1457*0cba2b28SAlexander V. Chernikov break; 1458*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 1459*0cba2b28SAlexander V. Chernikov v->netgraph = strtol(n, &e, 10); 1460*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1461*0cba2b28SAlexander V. Chernikov etype = "netgraph"; 1462*0cba2b28SAlexander V. Chernikov break; 1463*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 1464*0cba2b28SAlexander V. Chernikov v->fib = strtol(n, &e, 10); 1465*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1466*0cba2b28SAlexander V. Chernikov etype = "fib"; 1467*0cba2b28SAlexander V. Chernikov break; 1468*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 1469*0cba2b28SAlexander V. Chernikov v->nat = strtol(n, &e, 10); 1470*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1471*0cba2b28SAlexander V. Chernikov etype = "nat"; 1472*0cba2b28SAlexander V. Chernikov break; 1473*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 1474*0cba2b28SAlexander V. Chernikov v->limit = strtol(n, &e, 10); 1475*0cba2b28SAlexander V. Chernikov if (*e != '\0') 1476*0cba2b28SAlexander V. Chernikov etype = "limit"; 1477*0cba2b28SAlexander V. Chernikov break; 1478*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 1479*0cba2b28SAlexander V. Chernikov if (strchr(n, '.') != NULL && 1480*0cba2b28SAlexander V. Chernikov inet_pton(AF_INET, n, &a4) == 1) { 1481*0cba2b28SAlexander V. Chernikov v->nh4 = ntohl(a4); 1482*0cba2b28SAlexander V. Chernikov break; 1483*0cba2b28SAlexander V. Chernikov } 1484*0cba2b28SAlexander V. Chernikov if (lookup_host(n, (struct in_addr *)&v->nh4) == 0) 1485*0cba2b28SAlexander V. Chernikov break; 1486*0cba2b28SAlexander V. Chernikov etype = "ipv4"; 1487ac35ff17SAlexander V. Chernikov break; 1488ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1489*0cba2b28SAlexander V. Chernikov if (isalpha(*n)) { 1490*0cba2b28SAlexander V. Chernikov if ((v->dscp = match_token(f_ipdscp, n)) != -1) 1491ac35ff17SAlexander V. Chernikov break; 1492*0cba2b28SAlexander V. Chernikov else 1493*0cba2b28SAlexander V. Chernikov etype = "DSCP code"; 1494*0cba2b28SAlexander V. Chernikov } else { 1495*0cba2b28SAlexander V. Chernikov v->dscp = strtol(n, &e, 10); 1496*0cba2b28SAlexander V. Chernikov if (v->dscp > 63 || *e != '\0') 1497*0cba2b28SAlexander V. Chernikov etype = "DSCP value"; 1498ac35ff17SAlexander V. Chernikov } 1499*0cba2b28SAlexander V. Chernikov break; 1500*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 1501*0cba2b28SAlexander V. Chernikov if (strchr(n, ':') != NULL && 1502*0cba2b28SAlexander V. Chernikov inet_pton(AF_INET6, n, &v->nh6) == 1) 1503*0cba2b28SAlexander V. Chernikov break; 1504*0cba2b28SAlexander V. Chernikov etype = "ipv6"; 1505*0cba2b28SAlexander V. Chernikov break; 1506*0cba2b28SAlexander V. Chernikov } 1507*0cba2b28SAlexander V. Chernikov 1508*0cba2b28SAlexander V. Chernikov if (etype != NULL) 1509*0cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Unable to parse %s as %s", n, etype); 1510*0cba2b28SAlexander V. Chernikov 1511*0cba2b28SAlexander V. Chernikov if (comma != NULL) 1512*0cba2b28SAlexander V. Chernikov *comma++ = ','; 1513*0cba2b28SAlexander V. Chernikov 1514*0cba2b28SAlexander V. Chernikov if ((n = comma) != NULL) 1515*0cba2b28SAlexander V. Chernikov continue; 1516*0cba2b28SAlexander V. Chernikov 1517*0cba2b28SAlexander V. Chernikov /* End of input. */ 1518*0cba2b28SAlexander V. Chernikov if (vmask != 0) 1519*0cba2b28SAlexander V. Chernikov errx(EX_USAGE, "Not enough fields inside value"); 1520*0cba2b28SAlexander V. Chernikov } 1521ac35ff17SAlexander V. Chernikov } 1522f1220db8SAlexander V. Chernikov 1523f1220db8SAlexander V. Chernikov /* 1524f1220db8SAlexander V. Chernikov * Compare table names. 1525f1220db8SAlexander V. Chernikov * Honor number comparison. 1526f1220db8SAlexander V. Chernikov */ 1527f1220db8SAlexander V. Chernikov static int 1528f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1529f1220db8SAlexander V. Chernikov { 1530f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1531f1220db8SAlexander V. Chernikov 1532f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1533f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1534f1220db8SAlexander V. Chernikov 153568394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1536f1220db8SAlexander V. Chernikov } 1537f1220db8SAlexander V. Chernikov 1538f1220db8SAlexander V. Chernikov /* 1539f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1540f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1541f1220db8SAlexander V. Chernikov * Returns 0 on success. 1542f1220db8SAlexander V. Chernikov */ 1543f1220db8SAlexander V. Chernikov static int 1544f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1545f1220db8SAlexander V. Chernikov { 154628ea4fa3SAlexander V. Chernikov ipfw_obj_lheader *olh; 1547f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1548f1220db8SAlexander V. Chernikov size_t sz; 1549f1220db8SAlexander V. Chernikov int i, error; 1550f1220db8SAlexander V. Chernikov 155128ea4fa3SAlexander V. Chernikov /* Start with reasonable default */ 155228ea4fa3SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1553f1220db8SAlexander V. Chernikov 155428ea4fa3SAlexander V. Chernikov for (;;) { 1555f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1556f1220db8SAlexander V. Chernikov return (ENOMEM); 1557f1220db8SAlexander V. Chernikov 1558f1220db8SAlexander V. Chernikov olh->size = sz; 155928ea4fa3SAlexander V. Chernikov error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz); 156028ea4fa3SAlexander V. Chernikov if (error == ENOMEM) { 156128ea4fa3SAlexander V. Chernikov sz = olh->size; 1562f1220db8SAlexander V. Chernikov free(olh); 156328ea4fa3SAlexander V. Chernikov continue; 156428ea4fa3SAlexander V. Chernikov } else if (error != 0) { 156528ea4fa3SAlexander V. Chernikov free(olh); 156628ea4fa3SAlexander V. Chernikov return (error); 1567f1220db8SAlexander V. Chernikov } 1568f1220db8SAlexander V. Chernikov 1569f1220db8SAlexander V. Chernikov if (sort != 0) 1570f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1571f1220db8SAlexander V. Chernikov 1572f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1573f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1574f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1575f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1576f1220db8SAlexander V. Chernikov } 1577f1220db8SAlexander V. Chernikov 1578f1220db8SAlexander V. Chernikov free(olh); 157928ea4fa3SAlexander V. Chernikov break; 158028ea4fa3SAlexander V. Chernikov } 1581f1220db8SAlexander V. Chernikov 1582f1220db8SAlexander V. Chernikov return (0); 1583f1220db8SAlexander V. Chernikov } 1584f1220db8SAlexander V. Chernikov 158528ea4fa3SAlexander V. Chernikov 1586f1220db8SAlexander V. Chernikov /* 1587f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1588720ee730SAlexander V. Chernikov * eXtended format. Allocate buffer large enough 1589720ee730SAlexander V. Chernikov * to store result. Called needs to free it later. 1590f1220db8SAlexander V. Chernikov * 1591f1220db8SAlexander V. Chernikov * Returns 0 on success. 1592f1220db8SAlexander V. Chernikov */ 1593f1220db8SAlexander V. Chernikov static int 1594720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1595f1220db8SAlexander V. Chernikov { 1596720ee730SAlexander V. Chernikov ipfw_obj_header *oh; 1597f1220db8SAlexander V. Chernikov size_t sz; 159881d3153dSAlexander V. Chernikov int error, c; 1599f1220db8SAlexander V. Chernikov 160081d3153dSAlexander V. Chernikov sz = 0; 1601720ee730SAlexander V. Chernikov oh = NULL; 1602720ee730SAlexander V. Chernikov error = 0; 1603720ee730SAlexander V. Chernikov for (c = 0; c < 8; c++) { 160481d3153dSAlexander V. Chernikov if (sz < i->size) 1605720ee730SAlexander V. Chernikov sz = i->size + 44; 1606720ee730SAlexander V. Chernikov if (oh != NULL) 1607720ee730SAlexander V. Chernikov free(oh); 1608720ee730SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1609720ee730SAlexander V. Chernikov continue; 1610720ee730SAlexander V. Chernikov table_fill_objheader(oh, i); 1611d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 161281d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1613d3a4f924SAlexander V. Chernikov 1614720ee730SAlexander V. Chernikov if (error == 0) { 1615720ee730SAlexander V. Chernikov *poh = oh; 1616720ee730SAlexander V. Chernikov return (0); 161781d3153dSAlexander V. Chernikov } 1618f1220db8SAlexander V. Chernikov 1619720ee730SAlexander V. Chernikov if (error != ENOMEM) 1620720ee730SAlexander V. Chernikov break; 1621720ee730SAlexander V. Chernikov } 1622720ee730SAlexander V. Chernikov free(oh); 1623720ee730SAlexander V. Chernikov 1624720ee730SAlexander V. Chernikov return (error); 1625f1220db8SAlexander V. Chernikov } 1626f1220db8SAlexander V. Chernikov 1627f1220db8SAlexander V. Chernikov /* 1628f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1629f1220db8SAlexander V. Chernikov */ 1630f1220db8SAlexander V. Chernikov static void 1631f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1632f1220db8SAlexander V. Chernikov { 163381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 163481d3153dSAlexander V. Chernikov uint32_t count; 1635f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1636f1220db8SAlexander V. Chernikov 1637f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 163881d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1639f1220db8SAlexander V. Chernikov 1640f1220db8SAlexander V. Chernikov if (need_header) 1641f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1642f1220db8SAlexander V. Chernikov 1643f1220db8SAlexander V. Chernikov count = i->count; 1644f1220db8SAlexander V. Chernikov while (count > 0) { 164581d3153dSAlexander V. Chernikov table_show_entry(i, tent); 164681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 164781d3153dSAlexander V. Chernikov count--; 164881d3153dSAlexander V. Chernikov } 164981d3153dSAlexander V. Chernikov } 165081d3153dSAlexander V. Chernikov 165181d3153dSAlexander V. Chernikov static void 1652*0cba2b28SAlexander V. Chernikov table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 1653*0cba2b28SAlexander V. Chernikov uint32_t vmask, int print_ip) 1654*0cba2b28SAlexander V. Chernikov { 1655*0cba2b28SAlexander V. Chernikov uint32_t flag, i, l; 1656*0cba2b28SAlexander V. Chernikov size_t sz; 1657*0cba2b28SAlexander V. Chernikov struct in_addr a4; 1658*0cba2b28SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN]; 1659*0cba2b28SAlexander V. Chernikov 1660*0cba2b28SAlexander V. Chernikov sz = bufsize; 1661*0cba2b28SAlexander V. Chernikov 1662*0cba2b28SAlexander V. Chernikov /* 1663*0cba2b28SAlexander V. Chernikov * Some shorthands for printing values: 1664*0cba2b28SAlexander V. Chernikov * legacy assumes all values are equal, so keep the first one. 1665*0cba2b28SAlexander V. Chernikov */ 1666*0cba2b28SAlexander V. Chernikov if (vmask == IPFW_VTYPE_LEGACY) { 1667*0cba2b28SAlexander V. Chernikov if (print_ip != 0) { 1668*0cba2b28SAlexander V. Chernikov flag = htonl(v->tag); 1669*0cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &flag, buf, sz); 1670*0cba2b28SAlexander V. Chernikov } else 1671*0cba2b28SAlexander V. Chernikov snprintf(buf, sz, "%u", v->tag); 1672*0cba2b28SAlexander V. Chernikov return; 1673*0cba2b28SAlexander V. Chernikov } 1674*0cba2b28SAlexander V. Chernikov 1675*0cba2b28SAlexander V. Chernikov for (i = 1; i < (1 << 31); i *= 2) { 1676*0cba2b28SAlexander V. Chernikov if ((flag = (vmask & i)) == 0) 1677*0cba2b28SAlexander V. Chernikov continue; 1678*0cba2b28SAlexander V. Chernikov l = 0; 1679*0cba2b28SAlexander V. Chernikov 1680*0cba2b28SAlexander V. Chernikov switch (flag) { 1681*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_TAG: 1682*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->tag); 1683*0cba2b28SAlexander V. Chernikov break; 1684*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_PIPE: 1685*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->pipe); 1686*0cba2b28SAlexander V. Chernikov break; 1687*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DIVERT: 1688*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->divert); 1689*0cba2b28SAlexander V. Chernikov break; 1690*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_SKIPTO: 1691*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->skipto); 1692*0cba2b28SAlexander V. Chernikov break; 1693*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NETGRAPH: 1694*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->netgraph); 1695*0cba2b28SAlexander V. Chernikov break; 1696*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_FIB: 1697*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->fib); 1698*0cba2b28SAlexander V. Chernikov break; 1699*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NAT: 1700*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->nat); 1701*0cba2b28SAlexander V. Chernikov break; 1702*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_LIMIT: 1703*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%u,", v->limit); 1704*0cba2b28SAlexander V. Chernikov break; 1705*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH4: 1706*0cba2b28SAlexander V. Chernikov a4.s_addr = htonl(v->nh4); 1707*0cba2b28SAlexander V. Chernikov inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); 1708*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 1709*0cba2b28SAlexander V. Chernikov break; 1710*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1711*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%d,", v->dscp); 1712*0cba2b28SAlexander V. Chernikov break; 1713*0cba2b28SAlexander V. Chernikov case IPFW_VTYPE_NH6: 1714*0cba2b28SAlexander V. Chernikov inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf)); 1715*0cba2b28SAlexander V. Chernikov l = snprintf(buf, sz, "%s,", abuf); 1716*0cba2b28SAlexander V. Chernikov break; 1717*0cba2b28SAlexander V. Chernikov } 1718*0cba2b28SAlexander V. Chernikov 1719*0cba2b28SAlexander V. Chernikov buf += l; 1720*0cba2b28SAlexander V. Chernikov sz -= l; 1721*0cba2b28SAlexander V. Chernikov } 1722*0cba2b28SAlexander V. Chernikov 1723*0cba2b28SAlexander V. Chernikov if (sz != bufsize) 1724*0cba2b28SAlexander V. Chernikov *(buf - 1) = '\0'; 1725*0cba2b28SAlexander V. Chernikov } 1726*0cba2b28SAlexander V. Chernikov 1727*0cba2b28SAlexander V. Chernikov static void 172881d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 172981d3153dSAlexander V. Chernikov { 1730*0cba2b28SAlexander V. Chernikov char *comma, tbuf[128], pval[128]; 1731914bffb6SAlexander V. Chernikov void *paddr; 1732914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 173381d3153dSAlexander V. Chernikov 1734*0cba2b28SAlexander V. Chernikov table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, 1735*0cba2b28SAlexander V. Chernikov co.do_value_as_ip); 1736914bffb6SAlexander V. Chernikov 1737f1220db8SAlexander V. Chernikov switch (i->type) { 1738c21034b7SAlexander V. Chernikov case IPFW_TABLE_ADDR: 1739f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 174081d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1741914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1742f1220db8SAlexander V. Chernikov break; 1743f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1744f1220db8SAlexander V. Chernikov /* Interface names */ 1745914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1746b23d5de9SAlexander V. Chernikov break; 1747b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1748b23d5de9SAlexander V. Chernikov /* numbers */ 1749914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1750b23d5de9SAlexander V. Chernikov break; 1751914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1752914bffb6SAlexander V. Chernikov /* flows */ 1753914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1754914bffb6SAlexander V. Chernikov comma = ""; 1755914bffb6SAlexander V. Chernikov 1756914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1757914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1758914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1759914bffb6SAlexander V. Chernikov else 1760914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1761914bffb6SAlexander V. Chernikov 1762914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1763914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1764914bffb6SAlexander V. Chernikov comma = ","; 1765914bffb6SAlexander V. Chernikov } 1766914bffb6SAlexander V. Chernikov 1767914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1768914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1769914bffb6SAlexander V. Chernikov comma = ","; 1770914bffb6SAlexander V. Chernikov } 1771914bffb6SAlexander V. Chernikov 1772914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1773914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1774914bffb6SAlexander V. Chernikov comma = ","; 1775914bffb6SAlexander V. Chernikov } 1776914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1777914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1778914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1779914bffb6SAlexander V. Chernikov else 1780914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1781914bffb6SAlexander V. Chernikov 1782914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1783914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1784914bffb6SAlexander V. Chernikov comma = ","; 1785914bffb6SAlexander V. Chernikov } 1786914bffb6SAlexander V. Chernikov 1787914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1788914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1789914bffb6SAlexander V. Chernikov comma = ","; 1790914bffb6SAlexander V. Chernikov } 1791914bffb6SAlexander V. Chernikov 1792914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1793f1220db8SAlexander V. Chernikov } 1794f1220db8SAlexander V. Chernikov } 1795f1220db8SAlexander V. Chernikov 17969d099b4fSAlexander V. Chernikov static int 1797*0cba2b28SAlexander V. Chernikov table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) 17989d099b4fSAlexander V. Chernikov { 17999d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 18009d099b4fSAlexander V. Chernikov size_t sz; 18019d099b4fSAlexander V. Chernikov int error; 18029d099b4fSAlexander V. Chernikov 18039d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 18049d099b4fSAlexander V. Chernikov sz = sizeof(req); 18059d099b4fSAlexander V. Chernikov 1806*0cba2b28SAlexander V. Chernikov error = do_get3(opcode, &req.opheader, &sz); 18079d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 18089d099b4fSAlexander V. Chernikov return (error); 18099d099b4fSAlexander V. Chernikov 18109d099b4fSAlexander V. Chernikov sz = req.size; 18119d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 18129d099b4fSAlexander V. Chernikov return (ENOMEM); 18139d099b4fSAlexander V. Chernikov 18149d099b4fSAlexander V. Chernikov olh->size = sz; 1815*0cba2b28SAlexander V. Chernikov if ((error = do_get3(opcode, &olh->opheader, &sz)) != 0) { 18169d099b4fSAlexander V. Chernikov free(olh); 18179d099b4fSAlexander V. Chernikov return (error); 18189d099b4fSAlexander V. Chernikov } 18199d099b4fSAlexander V. Chernikov 18209d099b4fSAlexander V. Chernikov *polh = olh; 18219d099b4fSAlexander V. Chernikov return (0); 18229d099b4fSAlexander V. Chernikov } 18239d099b4fSAlexander V. Chernikov 1824*0cba2b28SAlexander V. Chernikov static int 1825*0cba2b28SAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 1826*0cba2b28SAlexander V. Chernikov { 1827*0cba2b28SAlexander V. Chernikov 1828*0cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); 1829*0cba2b28SAlexander V. Chernikov } 1830*0cba2b28SAlexander V. Chernikov 1831*0cba2b28SAlexander V. Chernikov static int 1832*0cba2b28SAlexander V. Chernikov table_do_get_vlist(ipfw_obj_lheader **polh) 1833*0cba2b28SAlexander V. Chernikov { 1834*0cba2b28SAlexander V. Chernikov 1835*0cba2b28SAlexander V. Chernikov return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); 1836*0cba2b28SAlexander V. Chernikov } 1837*0cba2b28SAlexander V. Chernikov 18389d099b4fSAlexander V. Chernikov void 18399d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 18409d099b4fSAlexander V. Chernikov { 18419d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 18429d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 18439d099b4fSAlexander V. Chernikov int error, i; 18449d099b4fSAlexander V. Chernikov const char *atype; 18459d099b4fSAlexander V. Chernikov 18469d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 18479d099b4fSAlexander V. Chernikov if (error != 0) 18489d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 18499d099b4fSAlexander V. Chernikov 18509d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 18519d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 18529d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 18539d099b4fSAlexander V. Chernikov atype = "unknown"; 18548ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 18558ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 18569d099b4fSAlexander V. Chernikov 18579d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 18589d099b4fSAlexander V. Chernikov } 18599d099b4fSAlexander V. Chernikov 18609d099b4fSAlexander V. Chernikov free(olh); 18619d099b4fSAlexander V. Chernikov } 18629d099b4fSAlexander V. Chernikov 1863*0cba2b28SAlexander V. Chernikov 1864*0cba2b28SAlexander V. Chernikov /* Copy of current kernel table_value structure */ 1865*0cba2b28SAlexander V. Chernikov struct _table_value { 1866*0cba2b28SAlexander V. Chernikov uint32_t tag; /* O_TAG/O_TAGGED */ 1867*0cba2b28SAlexander V. Chernikov uint32_t pipe; /* O_PIPE/O_QUEUE */ 1868*0cba2b28SAlexander V. Chernikov uint16_t divert; /* O_DIVERT/O_TEE */ 1869*0cba2b28SAlexander V. Chernikov uint16_t skipto; /* skipto, CALLRET */ 1870*0cba2b28SAlexander V. Chernikov uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ 1871*0cba2b28SAlexander V. Chernikov uint32_t fib; /* O_SETFIB */ 1872*0cba2b28SAlexander V. Chernikov uint32_t nat; /* O_NAT */ 1873*0cba2b28SAlexander V. Chernikov uint32_t nh4; 1874*0cba2b28SAlexander V. Chernikov uint8_t dscp; 1875*0cba2b28SAlexander V. Chernikov uint8_t spare0[3]; 1876*0cba2b28SAlexander V. Chernikov /* -- 32 bytes -- */ 1877*0cba2b28SAlexander V. Chernikov struct in6_addr nh6; 1878*0cba2b28SAlexander V. Chernikov uint32_t limit; /* O_LIMIT */ 1879*0cba2b28SAlexander V. Chernikov uint32_t spare1; 1880*0cba2b28SAlexander V. Chernikov uint64_t refcnt; /* Number of references */ 1881*0cba2b28SAlexander V. Chernikov }; 1882*0cba2b28SAlexander V. Chernikov 1883*0cba2b28SAlexander V. Chernikov int 1884*0cba2b28SAlexander V. Chernikov compare_values(const void *_a, const void *_b) 1885*0cba2b28SAlexander V. Chernikov { 1886*0cba2b28SAlexander V. Chernikov struct _table_value *a, *b; 1887*0cba2b28SAlexander V. Chernikov 1888*0cba2b28SAlexander V. Chernikov a = (struct _table_value *)_a; 1889*0cba2b28SAlexander V. Chernikov b = (struct _table_value *)_b; 1890*0cba2b28SAlexander V. Chernikov 1891*0cba2b28SAlexander V. Chernikov if (a->spare1 < b->spare1) 1892*0cba2b28SAlexander V. Chernikov return (-1); 1893*0cba2b28SAlexander V. Chernikov else if (a->spare1 > b->spare1) 1894*0cba2b28SAlexander V. Chernikov return (1); 1895*0cba2b28SAlexander V. Chernikov 1896*0cba2b28SAlexander V. Chernikov return (0); 1897*0cba2b28SAlexander V. Chernikov } 1898*0cba2b28SAlexander V. Chernikov 1899*0cba2b28SAlexander V. Chernikov void 1900*0cba2b28SAlexander V. Chernikov ipfw_list_values(int ac, char *av[]) 1901*0cba2b28SAlexander V. Chernikov { 1902*0cba2b28SAlexander V. Chernikov ipfw_obj_lheader *olh; 1903*0cba2b28SAlexander V. Chernikov struct _table_value *v; 1904*0cba2b28SAlexander V. Chernikov int error, i; 1905*0cba2b28SAlexander V. Chernikov uint32_t vmask; 1906*0cba2b28SAlexander V. Chernikov char buf[128]; 1907*0cba2b28SAlexander V. Chernikov 1908*0cba2b28SAlexander V. Chernikov error = table_do_get_vlist(&olh); 1909*0cba2b28SAlexander V. Chernikov if (error != 0) 1910*0cba2b28SAlexander V. Chernikov err(EX_OSERR, "Unable to request value list"); 1911*0cba2b28SAlexander V. Chernikov 1912*0cba2b28SAlexander V. Chernikov vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ 1913*0cba2b28SAlexander V. Chernikov 1914*0cba2b28SAlexander V. Chernikov table_print_valheader(buf, sizeof(buf), vmask); 1915*0cba2b28SAlexander V. Chernikov printf("HEADER: %s\n", buf); 1916*0cba2b28SAlexander V. Chernikov v = (struct _table_value *)(olh + 1); 1917*0cba2b28SAlexander V. Chernikov qsort(v, olh->count, olh->objsize, compare_values); 1918*0cba2b28SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1919*0cba2b28SAlexander V. Chernikov table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, 1920*0cba2b28SAlexander V. Chernikov vmask, 0); 1921*0cba2b28SAlexander V. Chernikov printf("[%u] refs=%lu %s\n", v->spare1, v->refcnt, buf); 1922*0cba2b28SAlexander V. Chernikov v = (struct _table_value *)((caddr_t)v + olh->objsize); 1923*0cba2b28SAlexander V. Chernikov } 1924*0cba2b28SAlexander V. Chernikov 1925*0cba2b28SAlexander V. Chernikov free(olh); 1926*0cba2b28SAlexander V. Chernikov } 1927*0cba2b28SAlexander V. Chernikov 19286c2997ffSAlexander V. Chernikov int 19296c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 19306c2997ffSAlexander V. Chernikov { 19316c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 19326c2997ffSAlexander V. Chernikov 19336c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 19346c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 19356c2997ffSAlexander V. Chernikov 19366c2997ffSAlexander V. Chernikov if (a->set < b->set) 19376c2997ffSAlexander V. Chernikov return (-1); 19386c2997ffSAlexander V. Chernikov else if (a->set > b->set) 19396c2997ffSAlexander V. Chernikov return (1); 19406c2997ffSAlexander V. Chernikov 19416c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 19426c2997ffSAlexander V. Chernikov return (-1); 19436c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 19446c2997ffSAlexander V. Chernikov return (1); 19456c2997ffSAlexander V. Chernikov 19466c2997ffSAlexander V. Chernikov return (0); 19476c2997ffSAlexander V. Chernikov } 1948563b5ab1SAlexander V. Chernikov 1949563b5ab1SAlexander V. Chernikov int 19506c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1951563b5ab1SAlexander V. Chernikov { 1952563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1953563b5ab1SAlexander V. Chernikov uint16_t key; 1954563b5ab1SAlexander V. Chernikov 1955563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1956563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1957563b5ab1SAlexander V. Chernikov 1958563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1959563b5ab1SAlexander V. Chernikov return (-1); 1960563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1961563b5ab1SAlexander V. Chernikov return (1); 1962563b5ab1SAlexander V. Chernikov 1963563b5ab1SAlexander V. Chernikov return (0); 1964563b5ab1SAlexander V. Chernikov } 1965563b5ab1SAlexander V. Chernikov 1966563b5ab1SAlexander V. Chernikov /* 1967563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1968563b5ab1SAlexander V. Chernikov * Uses the following facts: 1969563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1970563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1971563b5ab1SAlexander V. Chernikov * 1972563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1973563b5ab1SAlexander V. Chernikov */ 1974563b5ab1SAlexander V. Chernikov char * 1975563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1976563b5ab1SAlexander V. Chernikov { 1977563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1978563b5ab1SAlexander V. Chernikov 1979563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 19806c2997ffSAlexander V. Chernikov compare_kntlv); 1981563b5ab1SAlexander V. Chernikov 1982563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1983563b5ab1SAlexander V. Chernikov return (ntlv->name); 1984563b5ab1SAlexander V. Chernikov 1985563b5ab1SAlexander V. Chernikov return (NULL); 1986563b5ab1SAlexander V. Chernikov } 1987563b5ab1SAlexander V. Chernikov 19886c2997ffSAlexander V. Chernikov void 19896c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 19906c2997ffSAlexander V. Chernikov { 19916c2997ffSAlexander V. Chernikov 19926c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 19936c2997ffSAlexander V. Chernikov } 19946c2997ffSAlexander V. Chernikov 19956c2997ffSAlexander V. Chernikov int 19966c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 19976c2997ffSAlexander V. Chernikov { 19986c2997ffSAlexander V. Chernikov int c, i, l; 19996c2997ffSAlexander V. Chernikov 20006c2997ffSAlexander V. Chernikov /* 20016c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 20026c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 2003ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 20046c2997ffSAlexander V. Chernikov */ 20056c2997ffSAlexander V. Chernikov l = strlen(tablename); 20066c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 20076c2997ffSAlexander V. Chernikov return (EINVAL); 20086c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 20096c2997ffSAlexander V. Chernikov c = tablename[i]; 20106c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 20116c2997ffSAlexander V. Chernikov c == '-' || c == '.') 20126c2997ffSAlexander V. Chernikov continue; 20136c2997ffSAlexander V. Chernikov return (EINVAL); 20146c2997ffSAlexander V. Chernikov } 20156c2997ffSAlexander V. Chernikov 2016ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 2017ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 2018ac35ff17SAlexander V. Chernikov return (EINVAL); 2019ac35ff17SAlexander V. Chernikov 20206c2997ffSAlexander V. Chernikov return (0); 20216c2997ffSAlexander V. Chernikov } 20226c2997ffSAlexander V. Chernikov 2023