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, 7035df97d0SAlexander V. Chernikov char *key, int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); 71ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 72ac35ff17SAlexander V. Chernikov char *arg, uint8_t type, uint8_t vtype); 73ac35ff17SAlexander V. Chernikov 74f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 75f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 76f1220db8SAlexander V. Chernikov 77f1220db8SAlexander V. Chernikov #ifndef s6_addr32 78f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 79f1220db8SAlexander V. Chernikov #endif 80f1220db8SAlexander V. Chernikov 81ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 82ac35ff17SAlexander V. Chernikov { "cidr", IPFW_TABLE_CIDR }, 83ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 84b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 85914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 86ac35ff17SAlexander V. Chernikov { NULL, 0 } 87ac35ff17SAlexander V. Chernikov }; 88ac35ff17SAlexander V. Chernikov 89ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 90ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 91ac35ff17SAlexander V. Chernikov { NULL, 0 } 92ac35ff17SAlexander V. Chernikov }; 93ac35ff17SAlexander V. Chernikov 94adf3b2b9SAlexander V. Chernikov static struct _s_x tablefvaltypes[] = { 95adf3b2b9SAlexander V. Chernikov { "ip", IPFW_VFTYPE_IP }, 96adf3b2b9SAlexander V. Chernikov { "number", IPFW_VFTYPE_U32 }, 97adf3b2b9SAlexander V. Chernikov { NULL, 0 } 98adf3b2b9SAlexander V. Chernikov }; 99adf3b2b9SAlexander V. Chernikov 100ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 101ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 102ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 10346d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 104ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 105ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 106adf3b2b9SAlexander V. Chernikov { "modify", TOK_MODIFY }, 10746d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 108ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 109358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 110ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 11181d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 1123a845e10SAlexander V. Chernikov { "atomic", TOK_ATOMIC }, 1134f43138aSAlexander V. Chernikov { "lock", TOK_LOCK }, 1144f43138aSAlexander V. Chernikov { "unlock", TOK_UNLOCK }, 115ac35ff17SAlexander V. Chernikov { NULL, 0 } 116ac35ff17SAlexander V. Chernikov }; 117ac35ff17SAlexander V. Chernikov 118f1220db8SAlexander V. Chernikov static int 119f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 120f1220db8SAlexander V. Chernikov { 121f1220db8SAlexander V. Chernikov struct hostent *he; 122f1220db8SAlexander V. Chernikov 123f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 124f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 125f1220db8SAlexander V. Chernikov return(-1); 126f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 127f1220db8SAlexander V. Chernikov } 128f1220db8SAlexander V. Chernikov return(0); 129f1220db8SAlexander V. Chernikov } 130f1220db8SAlexander V. Chernikov 131be695df9SAlexander V. Chernikov static int 132be695df9SAlexander V. Chernikov get_token(struct _s_x *table, char *string, char *errbase) 133be695df9SAlexander V. Chernikov { 134be695df9SAlexander V. Chernikov int tcmd; 135be695df9SAlexander V. Chernikov 136be695df9SAlexander V. Chernikov if ((tcmd = match_token_relaxed(table, string)) < 0) 137be695df9SAlexander V. Chernikov errx(EX_USAGE, "%s %s %s", 138be695df9SAlexander V. Chernikov (tcmd == 0) ? "invalid" : "ambiguous", errbase, string); 139be695df9SAlexander V. Chernikov 140be695df9SAlexander V. Chernikov return (tcmd); 141be695df9SAlexander V. Chernikov } 142be695df9SAlexander V. Chernikov 143f1220db8SAlexander V. Chernikov /* 144f1220db8SAlexander V. Chernikov * This one handles all table-related commands 145ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 146be695df9SAlexander V. Chernikov * ipfw table NAME modify ... 147ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 148be695df9SAlexander V. Chernikov * ipfw table NAME swap NAME 149be695df9SAlexander V. Chernikov * ipfw table NAME lock 150be695df9SAlexander V. Chernikov * ipfw table NAME unlock 151ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 152be695df9SAlexander V. Chernikov * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] .. 153be695df9SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] [addr[/masklen]] .. 154be695df9SAlexander V. Chernikov * ipfw table NAME lookup addr 155ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 156ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 157ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 158be695df9SAlexander V. Chernikov * ipfw table {NAME | all} detail 159f1220db8SAlexander V. Chernikov */ 160f1220db8SAlexander V. Chernikov void 161f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 162f1220db8SAlexander V. Chernikov { 163ac35ff17SAlexander V. Chernikov int do_add, is_all; 1643a845e10SAlexander V. Chernikov int atomic, error, tcmd; 165ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 166ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 167f1220db8SAlexander V. Chernikov char *tablename; 168ac35ff17SAlexander V. Chernikov uint32_t set; 169358b9d09SAlexander V. Chernikov void *arg; 170f1220db8SAlexander V. Chernikov 171ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 172ac35ff17SAlexander V. Chernikov is_all = 0; 173ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 174ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 175ac35ff17SAlexander V. Chernikov else 176ac35ff17SAlexander V. Chernikov set = 0; 177f1220db8SAlexander V. Chernikov 178f1220db8SAlexander V. Chernikov ac--; av++; 1799d099b4fSAlexander V. Chernikov NEED1("table needs name"); 180f1220db8SAlexander V. Chernikov tablename = *av; 181f1220db8SAlexander V. Chernikov 182ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 183ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 184ac35ff17SAlexander V. Chernikov oh.idx = 1; 185ac35ff17SAlexander V. Chernikov } else { 186ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 187ac35ff17SAlexander V. Chernikov is_all = 1; 188ac35ff17SAlexander V. Chernikov else 189ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 190ac35ff17SAlexander V. Chernikov } 191ac35ff17SAlexander V. Chernikov ac--; av++; 1929d099b4fSAlexander V. Chernikov NEED1("table needs command"); 193ac35ff17SAlexander V. Chernikov 194be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 1953a845e10SAlexander V. Chernikov /* Check if atomic operation was requested */ 1963a845e10SAlexander V. Chernikov atomic = 0; 1973a845e10SAlexander V. Chernikov if (tcmd == TOK_ATOMIC) { 1983a845e10SAlexander V. Chernikov ac--; av++; 1993a845e10SAlexander V. Chernikov NEED1("atomic needs command"); 200be695df9SAlexander V. Chernikov tcmd = get_token(tablecmds, *av, "table command"); 2013a845e10SAlexander V. Chernikov switch (tcmd) { 2023a845e10SAlexander V. Chernikov case TOK_ADD: 2033a845e10SAlexander V. Chernikov break; 2043a845e10SAlexander V. Chernikov default: 2053a845e10SAlexander V. Chernikov errx(EX_USAGE, "atomic is not compatible with %s", *av); 2063a845e10SAlexander V. Chernikov } 2073a845e10SAlexander V. Chernikov atomic = 1; 2083a845e10SAlexander V. Chernikov } 209ac35ff17SAlexander V. Chernikov 210ac35ff17SAlexander V. Chernikov switch (tcmd) { 211ac35ff17SAlexander V. Chernikov case TOK_LIST: 212ac35ff17SAlexander V. Chernikov case TOK_INFO: 213358b9d09SAlexander V. Chernikov case TOK_DETAIL: 214ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 215ac35ff17SAlexander V. Chernikov break; 216ac35ff17SAlexander V. Chernikov default: 217ac35ff17SAlexander V. Chernikov if (is_all != 0) 218ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 219ac35ff17SAlexander V. Chernikov } 220ac35ff17SAlexander V. Chernikov 221ac35ff17SAlexander V. Chernikov switch (tcmd) { 222ac35ff17SAlexander V. Chernikov case TOK_ADD: 223ac35ff17SAlexander V. Chernikov case TOK_DEL: 224f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 225f1220db8SAlexander V. Chernikov ac--; av++; 2263a845e10SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet, 2273a845e10SAlexander V. Chernikov co.do_quiet, atomic); 228ac35ff17SAlexander V. Chernikov break; 229ac35ff17SAlexander V. Chernikov case TOK_CREATE: 230f1220db8SAlexander V. Chernikov ac--; av++; 231ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 232ac35ff17SAlexander V. Chernikov break; 233adf3b2b9SAlexander V. Chernikov case TOK_MODIFY: 234adf3b2b9SAlexander V. Chernikov ac--; av++; 235adf3b2b9SAlexander V. Chernikov table_modify(&oh, ac, av); 236adf3b2b9SAlexander V. Chernikov break; 237ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 238ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 239ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 240ac35ff17SAlexander V. Chernikov break; 241ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 242f1220db8SAlexander V. Chernikov if (is_all == 0) { 243ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 244f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 245f1220db8SAlexander V. Chernikov tablename); 246f1220db8SAlexander V. Chernikov } else { 247ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 248f1220db8SAlexander V. Chernikov if (error != 0) 249f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 250f1220db8SAlexander V. Chernikov } 251ac35ff17SAlexander V. Chernikov break; 25246d52008SAlexander V. Chernikov case TOK_SWAP: 25346d52008SAlexander V. Chernikov ac--; av++; 25446d52008SAlexander V. Chernikov NEED1("second table name required"); 25546d52008SAlexander V. Chernikov table_swap(&oh, *av); 25646d52008SAlexander V. Chernikov break; 2574f43138aSAlexander V. Chernikov case TOK_LOCK: 2584f43138aSAlexander V. Chernikov case TOK_UNLOCK: 2594f43138aSAlexander V. Chernikov table_lock(&oh, (tcmd == TOK_LOCK)); 2604f43138aSAlexander V. Chernikov break; 261358b9d09SAlexander V. Chernikov case TOK_DETAIL: 262ac35ff17SAlexander V. Chernikov case TOK_INFO: 263358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 264f1220db8SAlexander V. Chernikov if (is_all == 0) { 265ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 266f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 267358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 268f1220db8SAlexander V. Chernikov } else { 269358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 270f1220db8SAlexander V. Chernikov if (error != 0) 271f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 272f1220db8SAlexander V. Chernikov } 273ac35ff17SAlexander V. Chernikov break; 274ac35ff17SAlexander V. Chernikov case TOK_LIST: 275ac35ff17SAlexander V. Chernikov if (is_all == 0) { 276ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 277ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 278ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 279ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 280f1220db8SAlexander V. Chernikov } else { 281ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 282ac35ff17SAlexander V. Chernikov if (error != 0) 283ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 284f1220db8SAlexander V. Chernikov } 285ac35ff17SAlexander V. Chernikov break; 28681d3153dSAlexander V. Chernikov case TOK_LOOKUP: 28781d3153dSAlexander V. Chernikov ac--; av++; 28881d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 28981d3153dSAlexander V. Chernikov break; 290f1220db8SAlexander V. Chernikov } 291f1220db8SAlexander V. Chernikov } 292f1220db8SAlexander V. Chernikov 293f1220db8SAlexander V. Chernikov static void 294ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 295f1220db8SAlexander V. Chernikov { 296f1220db8SAlexander V. Chernikov 297563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 298f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 299f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 300ac35ff17SAlexander V. Chernikov ntlv->set = set; 301f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 302f1220db8SAlexander V. Chernikov } 303f1220db8SAlexander V. Chernikov 304f1220db8SAlexander V. Chernikov static void 305f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 306f1220db8SAlexander V. Chernikov { 307f1220db8SAlexander V. Chernikov 308f1220db8SAlexander V. Chernikov oh->idx = 1; 30981d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 310ac35ff17SAlexander V. Chernikov } 311ac35ff17SAlexander V. Chernikov 312ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 313ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 314adf3b2b9SAlexander V. Chernikov { "ftype", TOK_FTYPE }, 315ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 316ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 3174c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 3184f43138aSAlexander V. Chernikov { "locked", TOK_LOCK }, 319ac35ff17SAlexander V. Chernikov { NULL, 0 } 320ac35ff17SAlexander V. Chernikov }; 321ac35ff17SAlexander V. Chernikov 322914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 323914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 324914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 325914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 326914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 327914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 328914bffb6SAlexander V. Chernikov { NULL, 0 } 329914bffb6SAlexander V. Chernikov }; 330914bffb6SAlexander V. Chernikov 331914bffb6SAlexander V. Chernikov int 332914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 333914bffb6SAlexander V. Chernikov { 334914bffb6SAlexander V. Chernikov uint8_t fset, fclear; 335914bffb6SAlexander V. Chernikov 336914bffb6SAlexander V. Chernikov /* Parse type options */ 337914bffb6SAlexander V. Chernikov switch(ttype) { 338914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 339914bffb6SAlexander V. Chernikov fset = fclear = 0; 340914bffb6SAlexander V. Chernikov fill_flags(flowtypecmds, p, &fset, 341914bffb6SAlexander V. Chernikov &fclear); 342914bffb6SAlexander V. Chernikov *tflags = fset; 343914bffb6SAlexander V. Chernikov break; 344914bffb6SAlexander V. Chernikov default: 345914bffb6SAlexander V. Chernikov return (EX_USAGE); 346914bffb6SAlexander V. Chernikov } 347914bffb6SAlexander V. Chernikov 348914bffb6SAlexander V. Chernikov return (0); 349914bffb6SAlexander V. Chernikov } 350914bffb6SAlexander V. Chernikov 351914bffb6SAlexander V. Chernikov void 352914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 353914bffb6SAlexander V. Chernikov { 354914bffb6SAlexander V. Chernikov const char *tname; 355914bffb6SAlexander V. Chernikov int l; 356914bffb6SAlexander V. Chernikov 357914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 358914bffb6SAlexander V. Chernikov tname = "unknown"; 359914bffb6SAlexander V. Chernikov 360914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 361914bffb6SAlexander V. Chernikov tbuf += l; 362914bffb6SAlexander V. Chernikov size -= l; 363914bffb6SAlexander V. Chernikov 364914bffb6SAlexander V. Chernikov switch(type) { 365914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 366914bffb6SAlexander V. Chernikov if (tflags != 0) { 367914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 368914bffb6SAlexander V. Chernikov l--; 369914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 370914bffb6SAlexander V. Chernikov } 371914bffb6SAlexander V. Chernikov break; 372914bffb6SAlexander V. Chernikov } 373914bffb6SAlexander V. Chernikov } 374914bffb6SAlexander V. Chernikov 375ac35ff17SAlexander V. Chernikov /* 376ac35ff17SAlexander V. Chernikov * Creates new table 377ac35ff17SAlexander V. Chernikov * 378ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 379ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 380ac35ff17SAlexander V. Chernikov * [ algo algoname ] 381ac35ff17SAlexander V. Chernikov */ 382ac35ff17SAlexander V. Chernikov static void 383ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 384ac35ff17SAlexander V. Chernikov { 385ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 386ac35ff17SAlexander V. Chernikov int error, tcmd, val; 387ac35ff17SAlexander V. Chernikov size_t sz; 388914bffb6SAlexander V. Chernikov char *p; 389ac35ff17SAlexander V. Chernikov char tbuf[128]; 390ac35ff17SAlexander V. Chernikov 391ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 392ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 393ac35ff17SAlexander V. Chernikov 394ac35ff17SAlexander V. Chernikov while (ac > 0) { 395be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 396ac35ff17SAlexander V. Chernikov ac--; av++; 397ac35ff17SAlexander V. Chernikov 398ac35ff17SAlexander V. Chernikov switch (tcmd) { 3994c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 4004c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 4014c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 4024c0c07a5SAlexander V. Chernikov ac--; av++; 4034c0c07a5SAlexander V. Chernikov break; 404ac35ff17SAlexander V. Chernikov case TOK_TYPE: 405ac35ff17SAlexander V. Chernikov NEED1("table type required"); 406914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 407914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 408914bffb6SAlexander V. Chernikov *p++ = '\0'; 409ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 410914bffb6SAlexander V. Chernikov if (val == -1) { 411914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 412914bffb6SAlexander V. Chernikov ", "); 413914bffb6SAlexander V. Chernikov errx(EX_USAGE, 414914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 415ac35ff17SAlexander V. Chernikov *av, tbuf); 416914bffb6SAlexander V. Chernikov } 417914bffb6SAlexander V. Chernikov xi.type = val; 418914bffb6SAlexander V. Chernikov if (p != NULL) { 419914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 420914bffb6SAlexander V. Chernikov if (error != 0) 421914bffb6SAlexander V. Chernikov errx(EX_USAGE, 422914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 423914bffb6SAlexander V. Chernikov } 424914bffb6SAlexander V. Chernikov ac--; av++; 425ac35ff17SAlexander V. Chernikov break; 426ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 427ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 428ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 429ac35ff17SAlexander V. Chernikov if (val != -1) { 430ac35ff17SAlexander V. Chernikov xi.vtype = val; 431ac35ff17SAlexander V. Chernikov ac--; av++; 432ac35ff17SAlexander V. Chernikov break; 433ac35ff17SAlexander V. Chernikov } 434ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 435ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 436ac35ff17SAlexander V. Chernikov *av, tbuf); 437ac35ff17SAlexander V. Chernikov break; 438adf3b2b9SAlexander V. Chernikov case TOK_FTYPE: 439adf3b2b9SAlexander V. Chernikov NEED1("table value format type required"); 440adf3b2b9SAlexander V. Chernikov val = match_token(tablefvaltypes, *av); 441adf3b2b9SAlexander V. Chernikov if (val != -1) { 442adf3b2b9SAlexander V. Chernikov xi.vftype = val; 443adf3b2b9SAlexander V. Chernikov ac--; av++; 444adf3b2b9SAlexander V. Chernikov break; 445adf3b2b9SAlexander V. Chernikov } 446adf3b2b9SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", "); 447adf3b2b9SAlexander V. Chernikov errx(EX_USAGE, "Unknown format type: %s. Supported: %s", 448adf3b2b9SAlexander V. Chernikov *av, tbuf); 449adf3b2b9SAlexander V. Chernikov break; 450ac35ff17SAlexander V. Chernikov case TOK_ALGO: 451ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 452ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 453ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 454ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 455ac35ff17SAlexander V. Chernikov ac--; av++; 456ac35ff17SAlexander V. Chernikov break; 4574f43138aSAlexander V. Chernikov case TOK_LOCK: 4584f43138aSAlexander V. Chernikov xi.flags |= IPFW_TGFLAGS_LOCKED; 4594f43138aSAlexander V. Chernikov break; 460ac35ff17SAlexander V. Chernikov } 461ac35ff17SAlexander V. Chernikov } 462ac35ff17SAlexander V. Chernikov 463*fd0869d5SAlexander V. Chernikov /* Set some defaults to preserve compability */ 464*fd0869d5SAlexander V. Chernikov if (xi.algoname[0] == '\0' && xi.type == 0) 465*fd0869d5SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 466*fd0869d5SAlexander V. Chernikov if (xi.vtype == 0) 467*fd0869d5SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 468*fd0869d5SAlexander V. Chernikov 469ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 470ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 471f1220db8SAlexander V. Chernikov } 472f1220db8SAlexander V. Chernikov 473f1220db8SAlexander V. Chernikov /* 474ac35ff17SAlexander V. Chernikov * Creates new table 475ac35ff17SAlexander V. Chernikov * 476ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 477ac35ff17SAlexander V. Chernikov * 478f1220db8SAlexander V. Chernikov * Returns 0 on success. 479f1220db8SAlexander V. Chernikov */ 480f1220db8SAlexander V. Chernikov static int 481ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 482f1220db8SAlexander V. Chernikov { 483ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 484ac35ff17SAlexander V. Chernikov int error; 485f1220db8SAlexander V. Chernikov 486ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 487ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 488ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 489ac35ff17SAlexander V. Chernikov 490ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 491ac35ff17SAlexander V. Chernikov 492ac35ff17SAlexander V. Chernikov return (error); 493ac35ff17SAlexander V. Chernikov } 494ac35ff17SAlexander V. Chernikov 495ac35ff17SAlexander V. Chernikov /* 496adf3b2b9SAlexander V. Chernikov * Modifies existing table 497adf3b2b9SAlexander V. Chernikov * 498adf3b2b9SAlexander V. Chernikov * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ] 499adf3b2b9SAlexander V. Chernikov */ 500adf3b2b9SAlexander V. Chernikov static void 501adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[]) 502adf3b2b9SAlexander V. Chernikov { 503adf3b2b9SAlexander V. Chernikov ipfw_xtable_info xi; 504adf3b2b9SAlexander V. Chernikov int error, tcmd, val; 505adf3b2b9SAlexander V. Chernikov size_t sz; 506adf3b2b9SAlexander V. Chernikov char tbuf[128]; 507adf3b2b9SAlexander V. Chernikov 508adf3b2b9SAlexander V. Chernikov sz = sizeof(tbuf); 509adf3b2b9SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 510adf3b2b9SAlexander V. Chernikov 511adf3b2b9SAlexander V. Chernikov while (ac > 0) { 512be695df9SAlexander V. Chernikov tcmd = get_token(tablenewcmds, *av, "option"); 513adf3b2b9SAlexander V. Chernikov ac--; av++; 514adf3b2b9SAlexander V. Chernikov 515adf3b2b9SAlexander V. Chernikov switch (tcmd) { 516adf3b2b9SAlexander V. Chernikov case TOK_LIMIT: 517adf3b2b9SAlexander V. Chernikov NEED1("limit value required"); 518adf3b2b9SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 519adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LIMIT; 520adf3b2b9SAlexander V. Chernikov ac--; av++; 521adf3b2b9SAlexander V. Chernikov break; 522adf3b2b9SAlexander V. Chernikov case TOK_FTYPE: 523adf3b2b9SAlexander V. Chernikov NEED1("table value format type required"); 524adf3b2b9SAlexander V. Chernikov val = match_token(tablefvaltypes, *av); 525adf3b2b9SAlexander V. Chernikov if (val != -1) { 526adf3b2b9SAlexander V. Chernikov xi.vftype = val; 527adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_FTYPE; 528adf3b2b9SAlexander V. Chernikov ac--; av++; 529adf3b2b9SAlexander V. Chernikov break; 530adf3b2b9SAlexander V. Chernikov } 531adf3b2b9SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", "); 532adf3b2b9SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 533adf3b2b9SAlexander V. Chernikov *av, tbuf); 534adf3b2b9SAlexander V. Chernikov break; 535adf3b2b9SAlexander V. Chernikov } 536adf3b2b9SAlexander V. Chernikov } 537adf3b2b9SAlexander V. Chernikov 538adf3b2b9SAlexander V. Chernikov if ((error = table_do_modify(oh, &xi)) != 0) 539adf3b2b9SAlexander V. Chernikov err(EX_OSERR, "Table modification failed"); 540adf3b2b9SAlexander V. Chernikov } 541adf3b2b9SAlexander V. Chernikov 542adf3b2b9SAlexander V. Chernikov /* 543adf3b2b9SAlexander V. Chernikov * Modifies existing table. 544adf3b2b9SAlexander V. Chernikov * 545adf3b2b9SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 546adf3b2b9SAlexander V. Chernikov * 547adf3b2b9SAlexander V. Chernikov * Returns 0 on success. 548adf3b2b9SAlexander V. Chernikov */ 549adf3b2b9SAlexander V. Chernikov static int 550adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 551adf3b2b9SAlexander V. Chernikov { 552adf3b2b9SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 553adf3b2b9SAlexander V. Chernikov int error; 554adf3b2b9SAlexander V. Chernikov 555adf3b2b9SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 556adf3b2b9SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 557adf3b2b9SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 558adf3b2b9SAlexander V. Chernikov 559adf3b2b9SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 560adf3b2b9SAlexander V. Chernikov 561adf3b2b9SAlexander V. Chernikov return (error); 562adf3b2b9SAlexander V. Chernikov } 5634f43138aSAlexander V. Chernikov 5644f43138aSAlexander V. Chernikov /* 5654f43138aSAlexander V. Chernikov * Locks or unlocks given table 5664f43138aSAlexander V. Chernikov */ 5674f43138aSAlexander V. Chernikov static void 5684f43138aSAlexander V. Chernikov table_lock(ipfw_obj_header *oh, int lock) 5694f43138aSAlexander V. Chernikov { 5704f43138aSAlexander V. Chernikov ipfw_xtable_info xi; 5714f43138aSAlexander V. Chernikov int error; 5724f43138aSAlexander V. Chernikov 5734f43138aSAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 5744f43138aSAlexander V. Chernikov 5754f43138aSAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LOCK; 5764f43138aSAlexander V. Chernikov xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; 5774f43138aSAlexander V. Chernikov 5784f43138aSAlexander V. Chernikov if ((error = table_do_modify(oh, &xi)) != 0) 5794f43138aSAlexander V. Chernikov err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); 5804f43138aSAlexander V. Chernikov } 5814f43138aSAlexander V. Chernikov 582adf3b2b9SAlexander V. Chernikov /* 583ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 584ac35ff17SAlexander V. Chernikov * Returns 0 on success. 585ac35ff17SAlexander V. Chernikov */ 586ac35ff17SAlexander V. Chernikov static int 587ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 588ac35ff17SAlexander V. Chernikov { 589ac35ff17SAlexander V. Chernikov 590ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 591f1220db8SAlexander V. Chernikov return (-1); 592f1220db8SAlexander V. Chernikov 593f1220db8SAlexander V. Chernikov return (0); 594f1220db8SAlexander V. Chernikov } 595f1220db8SAlexander V. Chernikov 596f1220db8SAlexander V. Chernikov /* 597ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 598f1220db8SAlexander V. Chernikov * Returns 0 on success. 599f1220db8SAlexander V. Chernikov */ 600f1220db8SAlexander V. Chernikov static int 601ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 602f1220db8SAlexander V. Chernikov { 603f1220db8SAlexander V. Chernikov 604ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 605f1220db8SAlexander V. Chernikov return (-1); 606f1220db8SAlexander V. Chernikov 607f1220db8SAlexander V. Chernikov return (0); 608f1220db8SAlexander V. Chernikov } 609f1220db8SAlexander V. Chernikov 61046d52008SAlexander V. Chernikov static int 61146d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 61246d52008SAlexander V. Chernikov { 61346d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 61446d52008SAlexander V. Chernikov int error; 61546d52008SAlexander V. Chernikov 61646d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 61746d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 61846d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 61946d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 62046d52008SAlexander V. Chernikov 62146d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 62246d52008SAlexander V. Chernikov 62346d52008SAlexander V. Chernikov return (error); 62446d52008SAlexander V. Chernikov } 62546d52008SAlexander V. Chernikov 62646d52008SAlexander V. Chernikov /* 62746d52008SAlexander V. Chernikov * Swaps given table with @second one. 62846d52008SAlexander V. Chernikov */ 62946d52008SAlexander V. Chernikov static int 63046d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 63146d52008SAlexander V. Chernikov { 63246d52008SAlexander V. Chernikov int error; 63346d52008SAlexander V. Chernikov 63446d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 63546d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 63646d52008SAlexander V. Chernikov 63746d52008SAlexander V. Chernikov error = table_do_swap(oh, second); 63846d52008SAlexander V. Chernikov 63946d52008SAlexander V. Chernikov switch (error) { 64046d52008SAlexander V. Chernikov case EINVAL: 64146d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 64246d52008SAlexander V. Chernikov case EFBIG: 64346d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 64446d52008SAlexander V. Chernikov } 64546d52008SAlexander V. Chernikov 64646d52008SAlexander V. Chernikov return (0); 64746d52008SAlexander V. Chernikov } 64846d52008SAlexander V. Chernikov 64946d52008SAlexander V. Chernikov 650f1220db8SAlexander V. Chernikov /* 651ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 652f1220db8SAlexander V. Chernikov * it inside @i. 653f1220db8SAlexander V. Chernikov * Returns 0 on success. 654f1220db8SAlexander V. Chernikov */ 655f1220db8SAlexander V. Chernikov static int 656ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 657f1220db8SAlexander V. Chernikov { 658f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 659ac35ff17SAlexander V. Chernikov int error; 660f1220db8SAlexander V. Chernikov size_t sz; 661f1220db8SAlexander V. Chernikov 662f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 663f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 664ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 665f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 666f1220db8SAlexander V. Chernikov 667ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 668ac35ff17SAlexander V. Chernikov return (error); 669f1220db8SAlexander V. Chernikov 670f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 671ac35ff17SAlexander V. Chernikov return (EINVAL); 672f1220db8SAlexander V. Chernikov 673f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 674f1220db8SAlexander V. Chernikov 675f1220db8SAlexander V. Chernikov return (0); 676f1220db8SAlexander V. Chernikov } 677f1220db8SAlexander V. Chernikov 6785f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 6795f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 6805f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 6815f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 6825f379342SAlexander V. Chernikov { NULL, 0 } 6835f379342SAlexander V. Chernikov }; 6845f379342SAlexander V. Chernikov 6855f379342SAlexander V. Chernikov struct ta_cldata { 6865f379342SAlexander V. Chernikov uint8_t taclass; 6875f379342SAlexander V. Chernikov uint8_t spare4; 6885f379342SAlexander V. Chernikov uint16_t itemsize; 6895f379342SAlexander V. Chernikov uint16_t itemsize6; 6905f379342SAlexander V. Chernikov uint32_t size; 6915f379342SAlexander V. Chernikov uint32_t count; 6925f379342SAlexander V. Chernikov }; 6935f379342SAlexander V. Chernikov 6945f379342SAlexander V. Chernikov /* 6955f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 6965f379342SAlexander V. Chernikov */ 6975f379342SAlexander V. Chernikov static void 6985f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 6995f379342SAlexander V. Chernikov const char *af, const char *taclass) 7005f379342SAlexander V. Chernikov { 7015f379342SAlexander V. Chernikov 7025f379342SAlexander V. Chernikov switch (d->taclass) { 7035f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 7045f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 7055f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7065f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7075f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 7085f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 7095f379342SAlexander V. Chernikov else 7105f379342SAlexander V. Chernikov printf(" size: %u items: %u " 7115f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7125f379342SAlexander V. Chernikov d->size, d->count, 7135f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 7145f379342SAlexander V. Chernikov break; 7155f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 7165f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 7175f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 7185f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 7195f379342SAlexander V. Chernikov d->count, d->itemsize); 7205f379342SAlexander V. Chernikov else 7215f379342SAlexander V. Chernikov printf(" items: %u " 7225f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 7235f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 7245f379342SAlexander V. Chernikov break; 7255f379342SAlexander V. Chernikov default: 7265f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 7275f379342SAlexander V. Chernikov } 7285f379342SAlexander V. Chernikov } 7295f379342SAlexander V. Chernikov 730f1220db8SAlexander V. Chernikov /* 731f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 732f1220db8SAlexander V. Chernikov */ 733f1220db8SAlexander V. Chernikov static int 734f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 735f1220db8SAlexander V. Chernikov { 736adf3b2b9SAlexander V. Chernikov const char *vtype, *vftype; 7375f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 7385f379342SAlexander V. Chernikov int afdata, afitem; 7395f379342SAlexander V. Chernikov struct ta_cldata d; 740adf3b2b9SAlexander V. Chernikov char ttype[64], tvtype[64]; 741f1220db8SAlexander V. Chernikov 742914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 743ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 744ac35ff17SAlexander V. Chernikov vtype = "unknown"; 745adf3b2b9SAlexander V. Chernikov if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL) 746adf3b2b9SAlexander V. Chernikov vftype = "unknown"; 747adf3b2b9SAlexander V. Chernikov if (strcmp(vtype, vftype) != 0) 748adf3b2b9SAlexander V. Chernikov snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype); 749adf3b2b9SAlexander V. Chernikov else 750adf3b2b9SAlexander V. Chernikov snprintf(tvtype, sizeof(tvtype), "%s", vtype); 751ac35ff17SAlexander V. Chernikov 752914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 7534f43138aSAlexander V. Chernikov if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) 7544f43138aSAlexander V. Chernikov printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); 7554f43138aSAlexander V. Chernikov else 756914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 757adf3b2b9SAlexander V. Chernikov printf(" valtype: %s, references: %u\n", tvtype, i->refcnt); 7589d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 759f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 7604c0c07a5SAlexander V. Chernikov if (i->limit > 0) 7614c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 762f1220db8SAlexander V. Chernikov 763358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 764358b9d09SAlexander V. Chernikov if (arg == NULL) 765358b9d09SAlexander V. Chernikov return (0); 766358b9d09SAlexander V. Chernikov 7675f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 7685f379342SAlexander V. Chernikov return (0); 7695f379342SAlexander V. Chernikov tainfo = &i->ta_info; 7705f379342SAlexander V. Chernikov 7715f379342SAlexander V. Chernikov afdata = 0; 7725f379342SAlexander V. Chernikov afitem = 0; 7735f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 7745f379342SAlexander V. Chernikov afdata = 1; 7755f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 7765f379342SAlexander V. Chernikov afitem = 1; 7775f379342SAlexander V. Chernikov 7785f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7795f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 7805f379342SAlexander V. Chernikov d.size = tainfo->size4; 7815f379342SAlexander V. Chernikov d.count = tainfo->count4; 7825f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 7835f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 7845f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 7855f379342SAlexander V. Chernikov else 7865f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7875f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7885f379342SAlexander V. Chernikov vtype = "unknown"; 7895f379342SAlexander V. Chernikov 7905f379342SAlexander V. Chernikov if (afdata == 0) { 7915f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 7925f379342SAlexander V. Chernikov } else { 7935f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 7945f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7955f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 7965f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7975f379342SAlexander V. Chernikov vtype = "unknown"; 7985f379342SAlexander V. Chernikov d.size = tainfo->size6; 7995f379342SAlexander V. Chernikov d.count = tainfo->count6; 8005f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 8015f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 8025f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 8035f379342SAlexander V. Chernikov } 8045f379342SAlexander V. Chernikov 805f1220db8SAlexander V. Chernikov return (0); 806f1220db8SAlexander V. Chernikov } 807f1220db8SAlexander V. Chernikov 808f1220db8SAlexander V. Chernikov 809f1220db8SAlexander V. Chernikov /* 810f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 811f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 812f1220db8SAlexander V. Chernikov */ 813f1220db8SAlexander V. Chernikov 814f1220db8SAlexander V. Chernikov static int 815f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 816f1220db8SAlexander V. Chernikov { 817f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 81881d3153dSAlexander V. Chernikov int error; 819f1220db8SAlexander V. Chernikov 820720ee730SAlexander V. Chernikov if ((error = table_do_get_list(i, &oh)) != 0) { 82181d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 82281d3153dSAlexander V. Chernikov return (error); 82381d3153dSAlexander V. Chernikov } 82481d3153dSAlexander V. Chernikov 825f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 826f1220db8SAlexander V. Chernikov 827f1220db8SAlexander V. Chernikov free(oh); 828f1220db8SAlexander V. Chernikov return (0); 829f1220db8SAlexander V. Chernikov } 830f1220db8SAlexander V. Chernikov 831f1220db8SAlexander V. Chernikov static int 832f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 833f1220db8SAlexander V. Chernikov { 834ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 835f1220db8SAlexander V. Chernikov 836ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 837ac35ff17SAlexander V. Chernikov 838ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 839ac35ff17SAlexander V. Chernikov 840ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 841f1220db8SAlexander V. Chernikov } 842f1220db8SAlexander V. Chernikov 843ac35ff17SAlexander V. Chernikov static int 844ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 8453a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent, int count, int atomic) 846ac35ff17SAlexander V. Chernikov { 847db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 8483a845e10SAlexander V. Chernikov ipfw_obj_tentry *tent_base; 8493a845e10SAlexander V. Chernikov caddr_t pbuf; 850db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 8513a845e10SAlexander V. Chernikov int error, i; 8523a845e10SAlexander V. Chernikov size_t sz; 853ac35ff17SAlexander V. Chernikov 8543a845e10SAlexander V. Chernikov sz = sizeof(*ctlv) + sizeof(*tent) * count; 8553a845e10SAlexander V. Chernikov if (count == 1) { 856ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 8573a845e10SAlexander V. Chernikov pbuf = xbuf; 8583a845e10SAlexander V. Chernikov } else { 8593a845e10SAlexander V. Chernikov if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) 8603a845e10SAlexander V. Chernikov return (ENOMEM); 8613a845e10SAlexander V. Chernikov } 8623a845e10SAlexander V. Chernikov 8633a845e10SAlexander V. Chernikov memcpy(pbuf, oh, sizeof(*oh)); 8643a845e10SAlexander V. Chernikov oh = (ipfw_obj_header *)pbuf; 865ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 866ac35ff17SAlexander V. Chernikov 867db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 8683a845e10SAlexander V. Chernikov ctlv->count = count; 8693a845e10SAlexander V. Chernikov ctlv->head.length = sz; 8703a845e10SAlexander V. Chernikov if (atomic != 0) 8713a845e10SAlexander V. Chernikov ctlv->flags |= IPFW_CTF_ATOMIC; 872db785d31SAlexander V. Chernikov 8733a845e10SAlexander V. Chernikov tent_base = tent; 8743a845e10SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent) * count); 875db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 8763a845e10SAlexander V. Chernikov for (i = 0; i < count; i++, tent++) { 877ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 8783a845e10SAlexander V. Chernikov tent->idx = oh->idx; 8793a845e10SAlexander V. Chernikov } 880ac35ff17SAlexander V. Chernikov 8813a845e10SAlexander V. Chernikov sz += sizeof(*oh); 8823a845e10SAlexander V. Chernikov error = do_get3(cmd, &oh->opheader, &sz); 8833a845e10SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 8843a845e10SAlexander V. Chernikov /* Copy result back to provided buffer */ 8853a845e10SAlexander V. Chernikov memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); 8863a845e10SAlexander V. Chernikov 8873a845e10SAlexander V. Chernikov if (pbuf != xbuf) 8883a845e10SAlexander V. Chernikov free(pbuf); 889ac35ff17SAlexander V. Chernikov 890ac35ff17SAlexander V. Chernikov return (error); 891ac35ff17SAlexander V. Chernikov } 892ac35ff17SAlexander V. Chernikov 893ac35ff17SAlexander V. Chernikov static void 8943a845e10SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, 8953a845e10SAlexander V. Chernikov int quiet, int update, int atomic) 896ac35ff17SAlexander V. Chernikov { 8973a845e10SAlexander V. Chernikov ipfw_obj_tentry *ptent, tent, *tent_buf; 89881d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 899ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 9003a845e10SAlexander V. Chernikov int cmd, count, error, i, ignored; 9013a845e10SAlexander V. Chernikov char *texterr, *etxt, *px; 902ac35ff17SAlexander V. Chernikov 903ac35ff17SAlexander V. Chernikov if (ac == 0) 904ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 905ac35ff17SAlexander V. Chernikov 906ac35ff17SAlexander V. Chernikov if (add != 0) { 907ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 9084c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 909ac35ff17SAlexander V. Chernikov } else { 910ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 9114c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 912ac35ff17SAlexander V. Chernikov } 913ac35ff17SAlexander V. Chernikov 9143a845e10SAlexander V. Chernikov /* 9153a845e10SAlexander V. Chernikov * Calculate number of entries: 9163a845e10SAlexander V. Chernikov * Assume [key val] x N for add 9173a845e10SAlexander V. Chernikov * and 9183a845e10SAlexander V. Chernikov * key x N for delete 9193a845e10SAlexander V. Chernikov */ 9203a845e10SAlexander V. Chernikov count = (add != 0) ? ac / 2 + 1 : ac; 9213a845e10SAlexander V. Chernikov 9223a845e10SAlexander V. Chernikov if (count <= 1) { 9233a845e10SAlexander V. Chernikov /* Adding single entry with/without value */ 9243a845e10SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 9253a845e10SAlexander V. Chernikov tent_buf = &tent; 9263a845e10SAlexander V. Chernikov } else { 9273a845e10SAlexander V. Chernikov 9283a845e10SAlexander V. Chernikov if ((tent_buf = calloc(count, sizeof(tent))) == NULL) 9293a845e10SAlexander V. Chernikov errx(EX_OSERR, 9303a845e10SAlexander V. Chernikov "Unable to allocate memory for all entries"); 9313a845e10SAlexander V. Chernikov } 9323a845e10SAlexander V. Chernikov ptent = tent_buf; 9333a845e10SAlexander V. Chernikov 9343a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 9353a845e10SAlexander V. Chernikov count = 0; 9363a845e10SAlexander V. Chernikov while (ac > 0) { 93735df97d0SAlexander V. Chernikov tentry_fill_key(oh, ptent, *av, add, &type, &vtype, &xi); 9383a845e10SAlexander V. Chernikov 9393a845e10SAlexander V. Chernikov /* 9403a845e10SAlexander V. Chernikov * compability layer: auto-create table if not exists 9413a845e10SAlexander V. Chernikov */ 9423a845e10SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 9433a845e10SAlexander V. Chernikov xi.type = type; 9443a845e10SAlexander V. Chernikov xi.vtype = vtype; 9453a845e10SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, 9463a845e10SAlexander V. Chernikov sizeof(xi.tablename)); 9473a845e10SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info " 9483a845e10SAlexander V. Chernikov "non-existent table %s. (auto-created)\n", 9493a845e10SAlexander V. Chernikov xi.tablename); 9503a845e10SAlexander V. Chernikov table_do_create(oh, &xi); 9513a845e10SAlexander V. Chernikov } 9523a845e10SAlexander V. Chernikov 9533a845e10SAlexander V. Chernikov oh->ntlv.type = type; 9543a845e10SAlexander V. Chernikov ac--; av++; 9553a845e10SAlexander V. Chernikov 9563a845e10SAlexander V. Chernikov if (add != 0 && ac > 0) { 9573a845e10SAlexander V. Chernikov tentry_fill_value(oh, ptent, *av, type, vtype); 9583a845e10SAlexander V. Chernikov ac--; av++; 9593a845e10SAlexander V. Chernikov } 9603a845e10SAlexander V. Chernikov 9613a845e10SAlexander V. Chernikov if (update != 0) 9623a845e10SAlexander V. Chernikov ptent->head.flags |= IPFW_TF_UPDATE; 9633a845e10SAlexander V. Chernikov 9643a845e10SAlexander V. Chernikov count++; 9653a845e10SAlexander V. Chernikov ptent++; 9663a845e10SAlexander V. Chernikov } 9673a845e10SAlexander V. Chernikov 9683a845e10SAlexander V. Chernikov error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 9693a845e10SAlexander V. Chernikov 9703a845e10SAlexander V. Chernikov /* 9713a845e10SAlexander V. Chernikov * Compatibility stuff: do not yell on duplicate keys or 9723a845e10SAlexander V. Chernikov * failed deletions. 9733a845e10SAlexander V. Chernikov */ 9743a845e10SAlexander V. Chernikov if (error == 0 || (error == EEXIST && add != 0) || 9753a845e10SAlexander V. Chernikov (error == ENOENT && add == 0)) { 9763a845e10SAlexander V. Chernikov if (quiet != 0) { 9773a845e10SAlexander V. Chernikov if (tent_buf != &tent) 9783a845e10SAlexander V. Chernikov free(tent_buf); 9793a845e10SAlexander V. Chernikov return; 9803a845e10SAlexander V. Chernikov } 9813a845e10SAlexander V. Chernikov } 9823a845e10SAlexander V. Chernikov 9833a845e10SAlexander V. Chernikov /* Report results back */ 9843a845e10SAlexander V. Chernikov ptent = tent_buf; 9853a845e10SAlexander V. Chernikov for (i = 0; i < count; ptent++, i++) { 9863a845e10SAlexander V. Chernikov ignored = 0; 9873a845e10SAlexander V. Chernikov switch (ptent->result) { 9883a845e10SAlexander V. Chernikov case IPFW_TR_ADDED: 9893a845e10SAlexander V. Chernikov px = "added"; 9903a845e10SAlexander V. Chernikov break; 9913a845e10SAlexander V. Chernikov case IPFW_TR_DELETED: 9923a845e10SAlexander V. Chernikov px = "deleted"; 9933a845e10SAlexander V. Chernikov break; 9943a845e10SAlexander V. Chernikov case IPFW_TR_UPDATED: 9953a845e10SAlexander V. Chernikov px = "updated"; 9963a845e10SAlexander V. Chernikov break; 9973a845e10SAlexander V. Chernikov case IPFW_TR_LIMIT: 9983a845e10SAlexander V. Chernikov px = "limit"; 9993a845e10SAlexander V. Chernikov ignored = 1; 10003a845e10SAlexander V. Chernikov break; 10013a845e10SAlexander V. Chernikov case IPFW_TR_ERROR: 10023a845e10SAlexander V. Chernikov px = "error"; 10033a845e10SAlexander V. Chernikov ignored = 1; 10043a845e10SAlexander V. Chernikov break; 10053a845e10SAlexander V. Chernikov case IPFW_TR_NOTFOUND: 10063a845e10SAlexander V. Chernikov px = "notfound"; 10073a845e10SAlexander V. Chernikov ignored = 1; 10083a845e10SAlexander V. Chernikov break; 10093a845e10SAlexander V. Chernikov case IPFW_TR_EXISTS: 10103a845e10SAlexander V. Chernikov px = "exists"; 10113a845e10SAlexander V. Chernikov ignored = 1; 10123a845e10SAlexander V. Chernikov break; 10133a845e10SAlexander V. Chernikov case IPFW_TR_IGNORED: 10143a845e10SAlexander V. Chernikov px = "ignored"; 10153a845e10SAlexander V. Chernikov ignored = 1; 10163a845e10SAlexander V. Chernikov break; 10173a845e10SAlexander V. Chernikov default: 10183a845e10SAlexander V. Chernikov px = "unknown"; 10193a845e10SAlexander V. Chernikov ignored = 1; 10203a845e10SAlexander V. Chernikov } 10213a845e10SAlexander V. Chernikov 10223a845e10SAlexander V. Chernikov if (error != 0 && atomic != 0 && ignored == 0) 10233a845e10SAlexander V. Chernikov printf("%s(reverted): ", px); 10243a845e10SAlexander V. Chernikov else 10253a845e10SAlexander V. Chernikov printf("%s: ", px); 10263a845e10SAlexander V. Chernikov 10273a845e10SAlexander V. Chernikov table_show_entry(&xi, ptent); 10283a845e10SAlexander V. Chernikov } 10293a845e10SAlexander V. Chernikov 10303a845e10SAlexander V. Chernikov if (tent_buf != &tent) 10313a845e10SAlexander V. Chernikov free(tent_buf); 10323a845e10SAlexander V. Chernikov 10333a845e10SAlexander V. Chernikov if (error == 0) 10344c0c07a5SAlexander V. Chernikov return; 10354c0c07a5SAlexander V. Chernikov 10364c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 10374c0c07a5SAlexander V. Chernikov switch (error) { 10384c0c07a5SAlexander V. Chernikov case EEXIST: 10394c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 10404c0c07a5SAlexander V. Chernikov break; 10414c0c07a5SAlexander V. Chernikov case EFBIG: 10424c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 10434c0c07a5SAlexander V. Chernikov break; 10444c0c07a5SAlexander V. Chernikov case ESRCH: 10454c0c07a5SAlexander V. Chernikov etxt = "table not found"; 10464c0c07a5SAlexander V. Chernikov break; 10474c0c07a5SAlexander V. Chernikov case ENOENT: 10484c0c07a5SAlexander V. Chernikov etxt = "record not found"; 10494c0c07a5SAlexander V. Chernikov break; 10504f43138aSAlexander V. Chernikov case EACCES: 10514f43138aSAlexander V. Chernikov etxt = "table is locked"; 10524f43138aSAlexander V. Chernikov break; 10534c0c07a5SAlexander V. Chernikov default: 10544c0c07a5SAlexander V. Chernikov etxt = strerror(error); 10554c0c07a5SAlexander V. Chernikov } 10564c0c07a5SAlexander V. Chernikov 10574c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 1058ac35ff17SAlexander V. Chernikov } 1059ac35ff17SAlexander V. Chernikov 106081d3153dSAlexander V. Chernikov static int 106181d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 106281d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 106381d3153dSAlexander V. Chernikov { 106481d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 106581d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 106681d3153dSAlexander V. Chernikov uint8_t type, vtype; 106781d3153dSAlexander V. Chernikov int error; 106881d3153dSAlexander V. Chernikov size_t sz; 106981d3153dSAlexander V. Chernikov 107081d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 107181d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 107281d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 107381d3153dSAlexander V. Chernikov 107481d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 107581d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 107681d3153dSAlexander V. Chernikov tent->idx = 1; 107781d3153dSAlexander V. Chernikov 107835df97d0SAlexander V. Chernikov tentry_fill_key(oh, tent, key, 0, &type, &vtype, xi); 107981d3153dSAlexander V. Chernikov oh->ntlv.type = type; 108081d3153dSAlexander V. Chernikov 108181d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 108281d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 108381d3153dSAlexander V. Chernikov return (error); 108481d3153dSAlexander V. Chernikov 108581d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 108681d3153dSAlexander V. Chernikov return (EINVAL); 108781d3153dSAlexander V. Chernikov 108881d3153dSAlexander V. Chernikov *xtent = *tent; 108981d3153dSAlexander V. Chernikov 109081d3153dSAlexander V. Chernikov return (0); 109181d3153dSAlexander V. Chernikov } 109281d3153dSAlexander V. Chernikov 109381d3153dSAlexander V. Chernikov static void 109481d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 109581d3153dSAlexander V. Chernikov { 109681d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 109781d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 1098914bffb6SAlexander V. Chernikov char key[64]; 109981d3153dSAlexander V. Chernikov int error; 110081d3153dSAlexander V. Chernikov 110181d3153dSAlexander V. Chernikov if (ac == 0) 110281d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 110381d3153dSAlexander V. Chernikov 1104914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 1105914bffb6SAlexander V. Chernikov 11063a845e10SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 1107914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 110881d3153dSAlexander V. Chernikov 110981d3153dSAlexander V. Chernikov switch (error) { 111081d3153dSAlexander V. Chernikov case 0: 111181d3153dSAlexander V. Chernikov break; 111281d3153dSAlexander V. Chernikov case ESRCH: 111381d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 111481d3153dSAlexander V. Chernikov case ENOENT: 111581d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 111681d3153dSAlexander V. Chernikov case ENOTSUP: 111781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 111881d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 111981d3153dSAlexander V. Chernikov default: 112081d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 112181d3153dSAlexander V. Chernikov } 112281d3153dSAlexander V. Chernikov 112381d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 112481d3153dSAlexander V. Chernikov } 1125ac35ff17SAlexander V. Chernikov 1126ac35ff17SAlexander V. Chernikov static void 1127914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1128914bffb6SAlexander V. Chernikov uint8_t tflags) 1129ac35ff17SAlexander V. Chernikov { 1130914bffb6SAlexander V. Chernikov char *p, *pp; 1131ac35ff17SAlexander V. Chernikov int mask, af; 1132914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 1133914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 1134ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 1135914bffb6SAlexander V. Chernikov uint16_t port; 1136914bffb6SAlexander V. Chernikov struct protoent *pent; 1137914bffb6SAlexander V. Chernikov struct servent *sent; 1138ac35ff17SAlexander V. Chernikov int masklen; 1139ac35ff17SAlexander V. Chernikov 1140ac35ff17SAlexander V. Chernikov masklen = 0; 1141ac35ff17SAlexander V. Chernikov af = 0; 1142ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 1143ac35ff17SAlexander V. Chernikov 1144ac35ff17SAlexander V. Chernikov switch (type) { 1145ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1146ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 1147ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 1148ac35ff17SAlexander V. Chernikov *p = '\0'; 1149ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 1150ac35ff17SAlexander V. Chernikov } 1151ac35ff17SAlexander V. Chernikov 1152ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 1153ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 1154ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 1155ac35ff17SAlexander V. Chernikov p + 1); 1156ac35ff17SAlexander V. Chernikov 1157ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 1158ac35ff17SAlexander V. Chernikov af = AF_INET; 1159ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 1160ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 1161ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 1162ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 1163ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 1164ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 1165ac35ff17SAlexander V. Chernikov p + 1); 1166ac35ff17SAlexander V. Chernikov 1167ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 1168ac35ff17SAlexander V. Chernikov af = AF_INET6; 1169ac35ff17SAlexander V. Chernikov } else { 1170ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 1171ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1172ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1173ac35ff17SAlexander V. Chernikov 1174ac35ff17SAlexander V. Chernikov masklen = 32; 1175ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 1176ac35ff17SAlexander V. Chernikov af = AF_INET; 1177ac35ff17SAlexander V. Chernikov } 1178ac35ff17SAlexander V. Chernikov break; 1179ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1180ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 1181ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1182ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 1183ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 1184ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 1185ac35ff17SAlexander V. Chernikov break; 1186b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1187ac35ff17SAlexander V. Chernikov /* Port or any other key */ 1188ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 1189ac35ff17SAlexander V. Chernikov if (*p != '\0') 1190ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 1191ac35ff17SAlexander V. Chernikov 1192ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 1193ac35ff17SAlexander V. Chernikov *pkey = key; 1194ac35ff17SAlexander V. Chernikov masklen = 32; 1195ac35ff17SAlexander V. Chernikov break; 1196914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1197914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1198914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 1199914bffb6SAlexander V. Chernikov af = 0; 1200914bffb6SAlexander V. Chernikov 1201914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6> */ 1202914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1203914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1204914bffb6SAlexander V. Chernikov *p++ = '\0'; 1205914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1206914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1207914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1208914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1209914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1210914bffb6SAlexander V. Chernikov af = AF_INET; 1211914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 1212914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1213914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1214914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1215914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1216914bffb6SAlexander V. Chernikov af = AF_INET6; 1217914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 1218914bffb6SAlexander V. Chernikov } 1219914bffb6SAlexander V. Chernikov 1220914bffb6SAlexander V. Chernikov arg = p; 1221914bffb6SAlexander V. Chernikov } 1222914bffb6SAlexander V. Chernikov 1223914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 1224914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 122535df97d0SAlexander V. Chernikov if (arg == NULL) 122635df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: proto missing"); 1227914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1228914bffb6SAlexander V. Chernikov *p++ = '\0'; 1229914bffb6SAlexander V. Chernikov 1230914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 1231914bffb6SAlexander V. Chernikov if (*pp != '\0') { 1232914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 1233914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 1234914bffb6SAlexander V. Chernikov arg); 1235914bffb6SAlexander V. Chernikov else 1236914bffb6SAlexander V. Chernikov key = pent->p_proto; 1237914bffb6SAlexander V. Chernikov } 1238914bffb6SAlexander V. Chernikov 1239914bffb6SAlexander V. Chernikov if (key > 255) 1240914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 1241914bffb6SAlexander V. Chernikov 1242914bffb6SAlexander V. Chernikov tfe->proto = key; 1243914bffb6SAlexander V. Chernikov 1244914bffb6SAlexander V. Chernikov arg = p; 1245914bffb6SAlexander V. Chernikov } 1246914bffb6SAlexander V. Chernikov 1247914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1248914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 124935df97d0SAlexander V. Chernikov if (arg == NULL) 125035df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: src port missing"); 1251914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1252914bffb6SAlexander V. Chernikov *p++ = '\0'; 1253914bffb6SAlexander V. Chernikov 1254914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1255914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1256914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1257914bffb6SAlexander V. Chernikov arg); 1258914bffb6SAlexander V. Chernikov else 1259914bffb6SAlexander V. Chernikov key = sent->s_port; 1260914bffb6SAlexander V. Chernikov } 1261914bffb6SAlexander V. Chernikov 1262914bffb6SAlexander V. Chernikov tfe->sport = port; 1263914bffb6SAlexander V. Chernikov 1264914bffb6SAlexander V. Chernikov arg = p; 1265914bffb6SAlexander V. Chernikov } 1266914bffb6SAlexander V. Chernikov 1267914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1268914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 126935df97d0SAlexander V. Chernikov if (arg == NULL) 127035df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst ip missing"); 1271914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1272914bffb6SAlexander V. Chernikov *p++ = '\0'; 1273914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1274914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1275914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1276914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1277914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1278914bffb6SAlexander V. Chernikov af = AF_INET; 1279914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 1280914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1281914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1282914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1283914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1284914bffb6SAlexander V. Chernikov af = AF_INET6; 1285914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1286914bffb6SAlexander V. Chernikov } 1287914bffb6SAlexander V. Chernikov 1288914bffb6SAlexander V. Chernikov arg = p; 1289914bffb6SAlexander V. Chernikov } 1290914bffb6SAlexander V. Chernikov 1291914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1292914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 129335df97d0SAlexander V. Chernikov if (arg == NULL) 129435df97d0SAlexander V. Chernikov errx(EX_DATAERR, "invalid key: dst port missing"); 1295914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1296914bffb6SAlexander V. Chernikov *p++ = '\0'; 1297914bffb6SAlexander V. Chernikov 1298914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1299914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1300914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1301914bffb6SAlexander V. Chernikov arg); 1302914bffb6SAlexander V. Chernikov else 1303914bffb6SAlexander V. Chernikov key = sent->s_port; 1304914bffb6SAlexander V. Chernikov } 1305914bffb6SAlexander V. Chernikov 1306914bffb6SAlexander V. Chernikov tfe->dport = port; 1307914bffb6SAlexander V. Chernikov 1308914bffb6SAlexander V. Chernikov arg = p; 1309914bffb6SAlexander V. Chernikov } 1310914bffb6SAlexander V. Chernikov 1311914bffb6SAlexander V. Chernikov tfe->af = af; 1312914bffb6SAlexander V. Chernikov 1313914bffb6SAlexander V. Chernikov break; 1314914bffb6SAlexander V. Chernikov 1315ac35ff17SAlexander V. Chernikov default: 1316ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1317ac35ff17SAlexander V. Chernikov } 1318ac35ff17SAlexander V. Chernikov 1319ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1320ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1321ac35ff17SAlexander V. Chernikov } 1322ac35ff17SAlexander V. Chernikov 1323ac35ff17SAlexander V. Chernikov static void 1324ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 132535df97d0SAlexander V. Chernikov int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 1326ac35ff17SAlexander V. Chernikov { 1327914bffb6SAlexander V. Chernikov uint8_t type, tflags, vtype; 1328ac35ff17SAlexander V. Chernikov int error; 1329db785d31SAlexander V. Chernikov char *del; 1330ac35ff17SAlexander V. Chernikov 1331ac35ff17SAlexander V. Chernikov type = 0; 1332914bffb6SAlexander V. Chernikov tflags = 0; 1333ac35ff17SAlexander V. Chernikov vtype = 0; 1334ac35ff17SAlexander V. Chernikov 13353a845e10SAlexander V. Chernikov if (xi->tablename[0] == '\0') 133681d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 13373a845e10SAlexander V. Chernikov else 13383a845e10SAlexander V. Chernikov error = 0; 133981d3153dSAlexander V. Chernikov 134081d3153dSAlexander V. Chernikov if (error == 0) { 134181d3153dSAlexander V. Chernikov /* Table found. */ 134281d3153dSAlexander V. Chernikov type = xi->type; 1343914bffb6SAlexander V. Chernikov tflags = xi->tflags; 134481d3153dSAlexander V. Chernikov vtype = xi->vtype; 134581d3153dSAlexander V. Chernikov } else { 134681d3153dSAlexander V. Chernikov if (error != ESRCH) 134781d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 134881d3153dSAlexander V. Chernikov oh->ntlv.name); 134935df97d0SAlexander V. Chernikov if (add == 0) 135035df97d0SAlexander V. Chernikov errx(EX_DATAERR, "Table %s does not exist", 135135df97d0SAlexander V. Chernikov oh->ntlv.name); 1352ac35ff17SAlexander V. Chernikov /* 135381d3153dSAlexander V. Chernikov * Table does not exist. 135481d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 135581d3153dSAlexander V. Chernikov * before failing. 1356ac35ff17SAlexander V. Chernikov */ 1357db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 1358db785d31SAlexander V. Chernikov *del = '\0'; 1359ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 1360ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 1361ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 1362ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 1363ac35ff17SAlexander V. Chernikov /* 136481d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 136581d3153dSAlexander V. Chernikov * This should be changed for MFC. 1366ac35ff17SAlexander V. Chernikov */ 136781d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 136881d3153dSAlexander V. Chernikov } else { 136981d3153dSAlexander V. Chernikov /* Inknown key */ 137081d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1371db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 137281d3153dSAlexander V. Chernikov } 1373db785d31SAlexander V. Chernikov if (del != NULL) 1374db785d31SAlexander V. Chernikov *del = '/'; 1375ac35ff17SAlexander V. Chernikov } 1376ac35ff17SAlexander V. Chernikov 1377914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1378ac35ff17SAlexander V. Chernikov 1379ac35ff17SAlexander V. Chernikov *ptype = type; 1380ac35ff17SAlexander V. Chernikov *pvtype = vtype; 1381ac35ff17SAlexander V. Chernikov } 1382ac35ff17SAlexander V. Chernikov 1383ac35ff17SAlexander V. Chernikov static void 1384ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1385ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 1386ac35ff17SAlexander V. Chernikov { 1387adf3b2b9SAlexander V. Chernikov uint32_t val; 1388ac35ff17SAlexander V. Chernikov char *p; 1389ac35ff17SAlexander V. Chernikov 1390adf3b2b9SAlexander V. Chernikov /* Try to interpret as number first */ 1391adf3b2b9SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1392adf3b2b9SAlexander V. Chernikov if (*p == '\0') 1393adf3b2b9SAlexander V. Chernikov return; 1394adf3b2b9SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &val) == 1) { 1395adf3b2b9SAlexander V. Chernikov tent->value = ntohl(val); 1396adf3b2b9SAlexander V. Chernikov return; 1397adf3b2b9SAlexander V. Chernikov } 1398adf3b2b9SAlexander V. Chernikov /* Try hostname */ 1399adf3b2b9SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) == 0) 1400adf3b2b9SAlexander V. Chernikov return; 1401adf3b2b9SAlexander V. Chernikov errx(EX_OSERR, "Unable to parse value %s", arg); 1402adf3b2b9SAlexander V. Chernikov #if 0 1403ac35ff17SAlexander V. Chernikov switch (vtype) { 1404ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 1405ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1406ac35ff17SAlexander V. Chernikov if (*p != '\0') 1407ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 1408ac35ff17SAlexander V. Chernikov break; 1409ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 1410ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 1411ac35ff17SAlexander V. Chernikov break; 1412ac35ff17SAlexander V. Chernikov /* Try hostname */ 1413ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 1414ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 1415ac35ff17SAlexander V. Chernikov break; 1416ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1417ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 1418ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 1419ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 1420ac35ff17SAlexander V. Chernikov } else { 1421ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 1422ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 1423ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 1424ac35ff17SAlexander V. Chernikov } 1425ac35ff17SAlexander V. Chernikov tent->value = code; 1426ac35ff17SAlexander V. Chernikov break; 1427ac35ff17SAlexander V. Chernikov default: 1428ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 1429ac35ff17SAlexander V. Chernikov } 1430adf3b2b9SAlexander V. Chernikov #endif 1431ac35ff17SAlexander V. Chernikov } 1432f1220db8SAlexander V. Chernikov 1433f1220db8SAlexander V. Chernikov /* 1434f1220db8SAlexander V. Chernikov * Compare table names. 1435f1220db8SAlexander V. Chernikov * Honor number comparison. 1436f1220db8SAlexander V. Chernikov */ 1437f1220db8SAlexander V. Chernikov static int 1438f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1439f1220db8SAlexander V. Chernikov { 1440f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1441f1220db8SAlexander V. Chernikov 1442f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1443f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1444f1220db8SAlexander V. Chernikov 144568394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1446f1220db8SAlexander V. Chernikov } 1447f1220db8SAlexander V. Chernikov 1448f1220db8SAlexander V. Chernikov /* 1449f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1450f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1451f1220db8SAlexander V. Chernikov * Returns 0 on success. 1452f1220db8SAlexander V. Chernikov */ 1453f1220db8SAlexander V. Chernikov static int 1454f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1455f1220db8SAlexander V. Chernikov { 145628ea4fa3SAlexander V. Chernikov ipfw_obj_lheader *olh; 1457f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1458f1220db8SAlexander V. Chernikov size_t sz; 1459f1220db8SAlexander V. Chernikov int i, error; 1460f1220db8SAlexander V. Chernikov 146128ea4fa3SAlexander V. Chernikov /* Start with reasonable default */ 146228ea4fa3SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1463f1220db8SAlexander V. Chernikov 146428ea4fa3SAlexander V. Chernikov for (;;) { 1465f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1466f1220db8SAlexander V. Chernikov return (ENOMEM); 1467f1220db8SAlexander V. Chernikov 1468f1220db8SAlexander V. Chernikov olh->size = sz; 146928ea4fa3SAlexander V. Chernikov error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz); 147028ea4fa3SAlexander V. Chernikov if (error == ENOMEM) { 147128ea4fa3SAlexander V. Chernikov sz = olh->size; 1472f1220db8SAlexander V. Chernikov free(olh); 147328ea4fa3SAlexander V. Chernikov continue; 147428ea4fa3SAlexander V. Chernikov } else if (error != 0) { 147528ea4fa3SAlexander V. Chernikov free(olh); 147628ea4fa3SAlexander V. Chernikov return (error); 1477f1220db8SAlexander V. Chernikov } 1478f1220db8SAlexander V. Chernikov 1479f1220db8SAlexander V. Chernikov if (sort != 0) 1480f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1481f1220db8SAlexander V. Chernikov 1482f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1483f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1484f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1485f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1486f1220db8SAlexander V. Chernikov } 1487f1220db8SAlexander V. Chernikov 1488f1220db8SAlexander V. Chernikov free(olh); 148928ea4fa3SAlexander V. Chernikov break; 149028ea4fa3SAlexander V. Chernikov } 1491f1220db8SAlexander V. Chernikov 1492f1220db8SAlexander V. Chernikov return (0); 1493f1220db8SAlexander V. Chernikov } 1494f1220db8SAlexander V. Chernikov 149528ea4fa3SAlexander V. Chernikov 1496f1220db8SAlexander V. Chernikov /* 1497f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1498720ee730SAlexander V. Chernikov * eXtended format. Allocate buffer large enough 1499720ee730SAlexander V. Chernikov * to store result. Called needs to free it later. 1500f1220db8SAlexander V. Chernikov * 1501f1220db8SAlexander V. Chernikov * Returns 0 on success. 1502f1220db8SAlexander V. Chernikov */ 1503f1220db8SAlexander V. Chernikov static int 1504720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1505f1220db8SAlexander V. Chernikov { 1506720ee730SAlexander V. Chernikov ipfw_obj_header *oh; 1507f1220db8SAlexander V. Chernikov size_t sz; 150881d3153dSAlexander V. Chernikov int error, c; 1509f1220db8SAlexander V. Chernikov 151081d3153dSAlexander V. Chernikov sz = 0; 1511720ee730SAlexander V. Chernikov oh = NULL; 1512720ee730SAlexander V. Chernikov error = 0; 1513720ee730SAlexander V. Chernikov for (c = 0; c < 8; c++) { 151481d3153dSAlexander V. Chernikov if (sz < i->size) 1515720ee730SAlexander V. Chernikov sz = i->size + 44; 1516720ee730SAlexander V. Chernikov if (oh != NULL) 1517720ee730SAlexander V. Chernikov free(oh); 1518720ee730SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1519720ee730SAlexander V. Chernikov continue; 1520720ee730SAlexander V. Chernikov table_fill_objheader(oh, i); 1521d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 152281d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1523d3a4f924SAlexander V. Chernikov 1524720ee730SAlexander V. Chernikov if (error == 0) { 1525720ee730SAlexander V. Chernikov *poh = oh; 1526720ee730SAlexander V. Chernikov return (0); 152781d3153dSAlexander V. Chernikov } 1528f1220db8SAlexander V. Chernikov 1529720ee730SAlexander V. Chernikov if (error != ENOMEM) 1530720ee730SAlexander V. Chernikov break; 1531720ee730SAlexander V. Chernikov } 1532720ee730SAlexander V. Chernikov free(oh); 1533720ee730SAlexander V. Chernikov 1534720ee730SAlexander V. Chernikov return (error); 1535f1220db8SAlexander V. Chernikov } 1536f1220db8SAlexander V. Chernikov 1537f1220db8SAlexander V. Chernikov /* 1538f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1539f1220db8SAlexander V. Chernikov */ 1540f1220db8SAlexander V. Chernikov static void 1541f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1542f1220db8SAlexander V. Chernikov { 154381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 154481d3153dSAlexander V. Chernikov uint32_t count; 1545f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1546f1220db8SAlexander V. Chernikov 1547f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 154881d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1549f1220db8SAlexander V. Chernikov 1550f1220db8SAlexander V. Chernikov if (need_header) 1551f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1552f1220db8SAlexander V. Chernikov 1553f1220db8SAlexander V. Chernikov count = i->count; 1554f1220db8SAlexander V. Chernikov while (count > 0) { 155581d3153dSAlexander V. Chernikov table_show_entry(i, tent); 155681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 155781d3153dSAlexander V. Chernikov count--; 155881d3153dSAlexander V. Chernikov } 155981d3153dSAlexander V. Chernikov } 156081d3153dSAlexander V. Chernikov 156181d3153dSAlexander V. Chernikov static void 156281d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 156381d3153dSAlexander V. Chernikov { 1564914bffb6SAlexander V. Chernikov char *comma, tbuf[128], pval[32]; 1565914bffb6SAlexander V. Chernikov void *paddr; 156681d3153dSAlexander V. Chernikov uint32_t tval; 1567914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 156881d3153dSAlexander V. Chernikov 156981d3153dSAlexander V. Chernikov tval = tent->value; 157081d3153dSAlexander V. Chernikov 1571adf3b2b9SAlexander V. Chernikov if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) { 1572914bffb6SAlexander V. Chernikov tval = htonl(tval); 1573914bffb6SAlexander V. Chernikov inet_ntop(AF_INET, &tval, pval, sizeof(pval)); 1574914bffb6SAlexander V. Chernikov } else 1575914bffb6SAlexander V. Chernikov snprintf(pval, sizeof(pval), "%u", tval); 1576914bffb6SAlexander V. Chernikov 1577f1220db8SAlexander V. Chernikov switch (i->type) { 1578f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1579f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 158081d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1581914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1582f1220db8SAlexander V. Chernikov break; 1583f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1584f1220db8SAlexander V. Chernikov /* Interface names */ 1585914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1586b23d5de9SAlexander V. Chernikov break; 1587b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1588b23d5de9SAlexander V. Chernikov /* numbers */ 1589914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1590b23d5de9SAlexander V. Chernikov break; 1591914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1592914bffb6SAlexander V. Chernikov /* flows */ 1593914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1594914bffb6SAlexander V. Chernikov comma = ""; 1595914bffb6SAlexander V. Chernikov 1596914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1597914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1598914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1599914bffb6SAlexander V. Chernikov else 1600914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1601914bffb6SAlexander V. Chernikov 1602914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1603914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1604914bffb6SAlexander V. Chernikov comma = ","; 1605914bffb6SAlexander V. Chernikov } 1606914bffb6SAlexander V. Chernikov 1607914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1608914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1609914bffb6SAlexander V. Chernikov comma = ","; 1610914bffb6SAlexander V. Chernikov } 1611914bffb6SAlexander V. Chernikov 1612914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1613914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1614914bffb6SAlexander V. Chernikov comma = ","; 1615914bffb6SAlexander V. Chernikov } 1616914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1617914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1618914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1619914bffb6SAlexander V. Chernikov else 1620914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1621914bffb6SAlexander V. Chernikov 1622914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1623914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1624914bffb6SAlexander V. Chernikov comma = ","; 1625914bffb6SAlexander V. Chernikov } 1626914bffb6SAlexander V. Chernikov 1627914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1628914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1629914bffb6SAlexander V. Chernikov comma = ","; 1630914bffb6SAlexander V. Chernikov } 1631914bffb6SAlexander V. Chernikov 1632914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1633f1220db8SAlexander V. Chernikov } 1634f1220db8SAlexander V. Chernikov } 1635f1220db8SAlexander V. Chernikov 16369d099b4fSAlexander V. Chernikov static int 16379d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 16389d099b4fSAlexander V. Chernikov { 16399d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 16409d099b4fSAlexander V. Chernikov size_t sz; 16419d099b4fSAlexander V. Chernikov int error; 16429d099b4fSAlexander V. Chernikov 16439d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 16449d099b4fSAlexander V. Chernikov sz = sizeof(req); 16459d099b4fSAlexander V. Chernikov 16469d099b4fSAlexander V. Chernikov error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); 16479d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 16489d099b4fSAlexander V. Chernikov return (error); 16499d099b4fSAlexander V. Chernikov 16509d099b4fSAlexander V. Chernikov sz = req.size; 16519d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 16529d099b4fSAlexander V. Chernikov return (ENOMEM); 16539d099b4fSAlexander V. Chernikov 16549d099b4fSAlexander V. Chernikov olh->size = sz; 16559d099b4fSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { 16569d099b4fSAlexander V. Chernikov free(olh); 16579d099b4fSAlexander V. Chernikov return (error); 16589d099b4fSAlexander V. Chernikov } 16599d099b4fSAlexander V. Chernikov 16609d099b4fSAlexander V. Chernikov *polh = olh; 16619d099b4fSAlexander V. Chernikov return (0); 16629d099b4fSAlexander V. Chernikov } 16639d099b4fSAlexander V. Chernikov 16649d099b4fSAlexander V. Chernikov void 16659d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 16669d099b4fSAlexander V. Chernikov { 16679d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 16689d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 16699d099b4fSAlexander V. Chernikov int error, i; 16709d099b4fSAlexander V. Chernikov const char *atype; 16719d099b4fSAlexander V. Chernikov 16729d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 16739d099b4fSAlexander V. Chernikov if (error != 0) 16749d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 16759d099b4fSAlexander V. Chernikov 16769d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 16779d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 16789d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 16799d099b4fSAlexander V. Chernikov atype = "unknown"; 16808ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 16818ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 16829d099b4fSAlexander V. Chernikov 16839d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 16849d099b4fSAlexander V. Chernikov } 16859d099b4fSAlexander V. Chernikov 16869d099b4fSAlexander V. Chernikov free(olh); 16879d099b4fSAlexander V. Chernikov } 16889d099b4fSAlexander V. Chernikov 16896c2997ffSAlexander V. Chernikov int 16906c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 16916c2997ffSAlexander V. Chernikov { 16926c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 16936c2997ffSAlexander V. Chernikov 16946c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 16956c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 16966c2997ffSAlexander V. Chernikov 16976c2997ffSAlexander V. Chernikov if (a->set < b->set) 16986c2997ffSAlexander V. Chernikov return (-1); 16996c2997ffSAlexander V. Chernikov else if (a->set > b->set) 17006c2997ffSAlexander V. Chernikov return (1); 17016c2997ffSAlexander V. Chernikov 17026c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 17036c2997ffSAlexander V. Chernikov return (-1); 17046c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 17056c2997ffSAlexander V. Chernikov return (1); 17066c2997ffSAlexander V. Chernikov 17076c2997ffSAlexander V. Chernikov return (0); 17086c2997ffSAlexander V. Chernikov } 1709563b5ab1SAlexander V. Chernikov 1710563b5ab1SAlexander V. Chernikov int 17116c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1712563b5ab1SAlexander V. Chernikov { 1713563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1714563b5ab1SAlexander V. Chernikov uint16_t key; 1715563b5ab1SAlexander V. Chernikov 1716563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1717563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1718563b5ab1SAlexander V. Chernikov 1719563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1720563b5ab1SAlexander V. Chernikov return (-1); 1721563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1722563b5ab1SAlexander V. Chernikov return (1); 1723563b5ab1SAlexander V. Chernikov 1724563b5ab1SAlexander V. Chernikov return (0); 1725563b5ab1SAlexander V. Chernikov } 1726563b5ab1SAlexander V. Chernikov 1727563b5ab1SAlexander V. Chernikov /* 1728563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1729563b5ab1SAlexander V. Chernikov * Uses the following facts: 1730563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1731563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1732563b5ab1SAlexander V. Chernikov * 1733563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1734563b5ab1SAlexander V. Chernikov */ 1735563b5ab1SAlexander V. Chernikov char * 1736563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1737563b5ab1SAlexander V. Chernikov { 1738563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1739563b5ab1SAlexander V. Chernikov 1740563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 17416c2997ffSAlexander V. Chernikov compare_kntlv); 1742563b5ab1SAlexander V. Chernikov 1743563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1744563b5ab1SAlexander V. Chernikov return (ntlv->name); 1745563b5ab1SAlexander V. Chernikov 1746563b5ab1SAlexander V. Chernikov return (NULL); 1747563b5ab1SAlexander V. Chernikov } 1748563b5ab1SAlexander V. Chernikov 17496c2997ffSAlexander V. Chernikov void 17506c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 17516c2997ffSAlexander V. Chernikov { 17526c2997ffSAlexander V. Chernikov 17536c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 17546c2997ffSAlexander V. Chernikov } 17556c2997ffSAlexander V. Chernikov 17566c2997ffSAlexander V. Chernikov int 17576c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 17586c2997ffSAlexander V. Chernikov { 17596c2997ffSAlexander V. Chernikov int c, i, l; 17606c2997ffSAlexander V. Chernikov 17616c2997ffSAlexander V. Chernikov /* 17626c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 17636c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 1764ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 17656c2997ffSAlexander V. Chernikov */ 17666c2997ffSAlexander V. Chernikov l = strlen(tablename); 17676c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 17686c2997ffSAlexander V. Chernikov return (EINVAL); 17696c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 17706c2997ffSAlexander V. Chernikov c = tablename[i]; 17716c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 17726c2997ffSAlexander V. Chernikov c == '-' || c == '.') 17736c2997ffSAlexander V. Chernikov continue; 17746c2997ffSAlexander V. Chernikov return (EINVAL); 17756c2997ffSAlexander V. Chernikov } 17766c2997ffSAlexander V. Chernikov 1777ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1778ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1779ac35ff17SAlexander V. Chernikov return (EINVAL); 1780ac35ff17SAlexander V. Chernikov 17816c2997ffSAlexander V. Chernikov return (0); 17826c2997ffSAlexander V. Chernikov } 17836c2997ffSAlexander V. Chernikov 1784