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 <stddef.h> /* offsetof */ 34f1220db8SAlexander V. Chernikov #include <stdio.h> 35f1220db8SAlexander V. Chernikov #include <stdlib.h> 36f1220db8SAlexander V. Chernikov #include <string.h> 37f1220db8SAlexander V. Chernikov #include <sysexits.h> 38f1220db8SAlexander V. Chernikov 39f1220db8SAlexander V. Chernikov #define IPFW_INTERNAL /* Access to protected structures in ip_fw.h. */ 40f1220db8SAlexander V. Chernikov 41f1220db8SAlexander V. Chernikov #include <net/if.h> 42f1220db8SAlexander V. Chernikov #include <net/if_dl.h> 43f1220db8SAlexander V. Chernikov #include <net/route.h> /* def. of struct route */ 44f1220db8SAlexander V. Chernikov #include <netinet/in.h> 45f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h> 46f1220db8SAlexander V. Chernikov #include <arpa/inet.h> 47f1220db8SAlexander V. Chernikov #include <alias.h> 48f1220db8SAlexander V. Chernikov 49f1220db8SAlexander V. Chernikov #include "ipfw2.h" 50f1220db8SAlexander V. Chernikov 51f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header); 52ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 53ac35ff17SAlexander V. Chernikov int add, int update); 54ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh); 55ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh); 56ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 57ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 5881d3153dSAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 59ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 60f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 61ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, 62ac35ff17SAlexander V. Chernikov uint16_t uidx); 63f1220db8SAlexander V. Chernikov 64f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 65f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 66f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh); 67f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 6881d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 69f1220db8SAlexander V. Chernikov 70ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 7181d3153dSAlexander V. Chernikov char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); 72ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 73ac35ff17SAlexander V. Chernikov char *arg, uint8_t type, uint8_t vtype); 74ac35ff17SAlexander V. Chernikov 75f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 76f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 77f1220db8SAlexander V. Chernikov 78f1220db8SAlexander V. Chernikov #ifndef s6_addr32 79f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 80f1220db8SAlexander V. Chernikov #endif 81f1220db8SAlexander V. Chernikov 82ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 83ac35ff17SAlexander V. Chernikov { "cidr", IPFW_TABLE_CIDR }, 84ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 85b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 86914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 87ac35ff17SAlexander V. Chernikov { NULL, 0 } 88ac35ff17SAlexander V. Chernikov }; 89ac35ff17SAlexander V. Chernikov 90ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 91ac35ff17SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 92ac35ff17SAlexander V. Chernikov { "ip", IPFW_VTYPE_IP }, 93ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 94ac35ff17SAlexander V. Chernikov { NULL, 0 } 95ac35ff17SAlexander V. Chernikov }; 96ac35ff17SAlexander V. Chernikov 97ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 98ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 99ac35ff17SAlexander V. Chernikov { "create", TOK_CREATE }, 100ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 101ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 102ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 103ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 104ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 10581d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 106ac35ff17SAlexander V. Chernikov { NULL, 0 } 107ac35ff17SAlexander V. Chernikov }; 108ac35ff17SAlexander V. Chernikov 109f1220db8SAlexander V. Chernikov static int 110f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 111f1220db8SAlexander V. Chernikov { 112f1220db8SAlexander V. Chernikov struct hostent *he; 113f1220db8SAlexander V. Chernikov 114f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 115f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 116f1220db8SAlexander V. Chernikov return(-1); 117f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 118f1220db8SAlexander V. Chernikov } 119f1220db8SAlexander V. Chernikov return(0); 120f1220db8SAlexander V. Chernikov } 121f1220db8SAlexander V. Chernikov 122f1220db8SAlexander V. Chernikov /* 123f1220db8SAlexander V. Chernikov * This one handles all table-related commands 124ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 125ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 126ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 127ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 128ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 129ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 130ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 131f1220db8SAlexander V. Chernikov */ 132f1220db8SAlexander V. Chernikov void 133f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 134f1220db8SAlexander V. Chernikov { 135ac35ff17SAlexander V. Chernikov int do_add, is_all; 136ac35ff17SAlexander V. Chernikov int error, tcmd; 137ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 138ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 139f1220db8SAlexander V. Chernikov char *tablename; 140ac35ff17SAlexander V. Chernikov uint32_t set; 141f1220db8SAlexander V. Chernikov 142ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 143ac35ff17SAlexander V. Chernikov is_all = 0; 144ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 145ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 146ac35ff17SAlexander V. Chernikov else 147ac35ff17SAlexander V. Chernikov set = 0; 148f1220db8SAlexander V. Chernikov 149f1220db8SAlexander V. Chernikov ac--; av++; 1509d099b4fSAlexander V. Chernikov NEED1("table needs name"); 151f1220db8SAlexander V. Chernikov tablename = *av; 152f1220db8SAlexander V. Chernikov 153ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 154ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 155ac35ff17SAlexander V. Chernikov oh.idx = 1; 156ac35ff17SAlexander V. Chernikov } else { 157ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 158ac35ff17SAlexander V. Chernikov is_all = 1; 159ac35ff17SAlexander V. Chernikov else 160ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 161ac35ff17SAlexander V. Chernikov } 162ac35ff17SAlexander V. Chernikov ac--; av++; 1639d099b4fSAlexander V. Chernikov NEED1("table needs command"); 164ac35ff17SAlexander V. Chernikov 165ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 166ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 167ac35ff17SAlexander V. Chernikov 168ac35ff17SAlexander V. Chernikov switch (tcmd) { 169ac35ff17SAlexander V. Chernikov case TOK_LIST: 170ac35ff17SAlexander V. Chernikov case TOK_INFO: 171ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 172ac35ff17SAlexander V. Chernikov break; 173ac35ff17SAlexander V. Chernikov default: 174ac35ff17SAlexander V. Chernikov if (is_all != 0) 175ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 176ac35ff17SAlexander V. Chernikov } 177ac35ff17SAlexander V. Chernikov 178ac35ff17SAlexander V. Chernikov switch (tcmd) { 179ac35ff17SAlexander V. Chernikov case TOK_ADD: 180ac35ff17SAlexander V. Chernikov case TOK_DEL: 181f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 182f1220db8SAlexander V. Chernikov ac--; av++; 183ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 184ac35ff17SAlexander V. Chernikov break; 185ac35ff17SAlexander V. Chernikov case TOK_CREATE: 186f1220db8SAlexander V. Chernikov ac--; av++; 187ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 188ac35ff17SAlexander V. Chernikov break; 189ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 190ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 191ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 192ac35ff17SAlexander V. Chernikov break; 193ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 194f1220db8SAlexander V. Chernikov if (is_all == 0) { 195ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 196f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 197f1220db8SAlexander V. Chernikov tablename); 198f1220db8SAlexander V. Chernikov } else { 199ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 200f1220db8SAlexander V. Chernikov if (error != 0) 201f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 202f1220db8SAlexander V. Chernikov } 203ac35ff17SAlexander V. Chernikov break; 204ac35ff17SAlexander V. Chernikov case TOK_INFO: 205f1220db8SAlexander V. Chernikov if (is_all == 0) { 206ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 207f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 208f1220db8SAlexander V. Chernikov table_show_info(&i, NULL); 209f1220db8SAlexander V. Chernikov } else { 210f1220db8SAlexander V. Chernikov error = tables_foreach(table_show_info, NULL, 1); 211f1220db8SAlexander V. Chernikov if (error != 0) 212f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 213f1220db8SAlexander V. Chernikov } 214ac35ff17SAlexander V. Chernikov break; 215ac35ff17SAlexander V. Chernikov case TOK_LIST: 216ac35ff17SAlexander V. Chernikov if (is_all == 0) { 217ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 218ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 219ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 220ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 221f1220db8SAlexander V. Chernikov } else { 222ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 223ac35ff17SAlexander V. Chernikov if (error != 0) 224ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 225f1220db8SAlexander V. Chernikov } 226ac35ff17SAlexander V. Chernikov break; 22781d3153dSAlexander V. Chernikov case TOK_LOOKUP: 22881d3153dSAlexander V. Chernikov ac--; av++; 22981d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 23081d3153dSAlexander V. Chernikov break; 231f1220db8SAlexander V. Chernikov } 232f1220db8SAlexander V. Chernikov } 233f1220db8SAlexander V. Chernikov 234f1220db8SAlexander V. Chernikov static void 235ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 236f1220db8SAlexander V. Chernikov { 237f1220db8SAlexander V. Chernikov 238563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 239f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 240f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 241ac35ff17SAlexander V. Chernikov ntlv->set = set; 242f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 243f1220db8SAlexander V. Chernikov } 244f1220db8SAlexander V. Chernikov 245f1220db8SAlexander V. Chernikov static void 246f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 247f1220db8SAlexander V. Chernikov { 248f1220db8SAlexander V. Chernikov 249f1220db8SAlexander V. Chernikov oh->idx = 1; 25081d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 251ac35ff17SAlexander V. Chernikov } 252ac35ff17SAlexander V. Chernikov 253ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 254ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 255ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 256ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 2574c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 258ac35ff17SAlexander V. Chernikov { NULL, 0 } 259ac35ff17SAlexander V. Chernikov }; 260ac35ff17SAlexander V. Chernikov 261914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 262914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 263914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 264914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 265914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 266914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 267914bffb6SAlexander V. Chernikov { NULL, 0 } 268914bffb6SAlexander V. Chernikov }; 269914bffb6SAlexander V. Chernikov 270914bffb6SAlexander V. Chernikov int 271914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 272914bffb6SAlexander V. Chernikov { 273914bffb6SAlexander V. Chernikov uint8_t fset, fclear; 274914bffb6SAlexander V. Chernikov 275914bffb6SAlexander V. Chernikov /* Parse type options */ 276914bffb6SAlexander V. Chernikov switch(ttype) { 277914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 278914bffb6SAlexander V. Chernikov fset = fclear = 0; 279914bffb6SAlexander V. Chernikov fill_flags(flowtypecmds, p, &fset, 280914bffb6SAlexander V. Chernikov &fclear); 281914bffb6SAlexander V. Chernikov *tflags = fset; 282914bffb6SAlexander V. Chernikov break; 283914bffb6SAlexander V. Chernikov default: 284914bffb6SAlexander V. Chernikov return (EX_USAGE); 285914bffb6SAlexander V. Chernikov } 286914bffb6SAlexander V. Chernikov 287914bffb6SAlexander V. Chernikov return (0); 288914bffb6SAlexander V. Chernikov } 289914bffb6SAlexander V. Chernikov 290914bffb6SAlexander V. Chernikov void 291914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 292914bffb6SAlexander V. Chernikov { 293914bffb6SAlexander V. Chernikov const char *tname; 294914bffb6SAlexander V. Chernikov int l; 295914bffb6SAlexander V. Chernikov 296914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 297914bffb6SAlexander V. Chernikov tname = "unknown"; 298914bffb6SAlexander V. Chernikov 299914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 300914bffb6SAlexander V. Chernikov tbuf += l; 301914bffb6SAlexander V. Chernikov size -= l; 302914bffb6SAlexander V. Chernikov 303914bffb6SAlexander V. Chernikov switch(type) { 304914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 305914bffb6SAlexander V. Chernikov if (tflags != 0) { 306914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 307914bffb6SAlexander V. Chernikov l--; 308914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 309914bffb6SAlexander V. Chernikov } 310914bffb6SAlexander V. Chernikov break; 311914bffb6SAlexander V. Chernikov } 312914bffb6SAlexander V. Chernikov } 313914bffb6SAlexander V. Chernikov 314ac35ff17SAlexander V. Chernikov /* 315ac35ff17SAlexander V. Chernikov * Creates new table 316ac35ff17SAlexander V. Chernikov * 317ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 318ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 319ac35ff17SAlexander V. Chernikov * [ algo algoname ] 320ac35ff17SAlexander V. Chernikov * 321ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 322ac35ff17SAlexander V. Chernikov */ 323ac35ff17SAlexander V. Chernikov static void 324ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 325ac35ff17SAlexander V. Chernikov { 326ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 327ac35ff17SAlexander V. Chernikov int error, tcmd, val; 328ac35ff17SAlexander V. Chernikov size_t sz; 329914bffb6SAlexander V. Chernikov char *p; 330ac35ff17SAlexander V. Chernikov char tbuf[128]; 331ac35ff17SAlexander V. Chernikov 332ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 333ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 334ac35ff17SAlexander V. Chernikov 335ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 336ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 337ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 338ac35ff17SAlexander V. Chernikov 339ac35ff17SAlexander V. Chernikov while (ac > 0) { 340ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 341ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 342ac35ff17SAlexander V. Chernikov ac--; av++; 343ac35ff17SAlexander V. Chernikov 344ac35ff17SAlexander V. Chernikov switch (tcmd) { 3454c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 3464c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 3474c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 3484c0c07a5SAlexander V. Chernikov ac--; av++; 3494c0c07a5SAlexander V. Chernikov break; 350ac35ff17SAlexander V. Chernikov case TOK_TYPE: 351ac35ff17SAlexander V. Chernikov NEED1("table type required"); 352914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 353914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 354914bffb6SAlexander V. Chernikov *p++ = '\0'; 355ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 356914bffb6SAlexander V. Chernikov if (val == -1) { 357914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 358914bffb6SAlexander V. Chernikov ", "); 359914bffb6SAlexander V. Chernikov errx(EX_USAGE, 360914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 361ac35ff17SAlexander V. Chernikov *av, tbuf); 362914bffb6SAlexander V. Chernikov } 363914bffb6SAlexander V. Chernikov xi.type = val; 364914bffb6SAlexander V. Chernikov if (p != NULL) { 365914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 366914bffb6SAlexander V. Chernikov if (error != 0) 367914bffb6SAlexander V. Chernikov errx(EX_USAGE, 368914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 369914bffb6SAlexander V. Chernikov } 370914bffb6SAlexander V. Chernikov ac--; av++; 371ac35ff17SAlexander V. Chernikov break; 372ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 373ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 374ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 375ac35ff17SAlexander V. Chernikov if (val != -1) { 376ac35ff17SAlexander V. Chernikov xi.vtype = val; 377ac35ff17SAlexander V. Chernikov ac--; av++; 378ac35ff17SAlexander V. Chernikov break; 379ac35ff17SAlexander V. Chernikov } 380ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 381ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 382ac35ff17SAlexander V. Chernikov *av, tbuf); 383ac35ff17SAlexander V. Chernikov break; 384ac35ff17SAlexander V. Chernikov case TOK_ALGO: 385ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 386ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 387ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 388ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 389ac35ff17SAlexander V. Chernikov ac--; av++; 390ac35ff17SAlexander V. Chernikov break; 391ac35ff17SAlexander V. Chernikov } 392ac35ff17SAlexander V. Chernikov } 393ac35ff17SAlexander V. Chernikov 394ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 395ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 396f1220db8SAlexander V. Chernikov } 397f1220db8SAlexander V. Chernikov 398f1220db8SAlexander V. Chernikov /* 399ac35ff17SAlexander V. Chernikov * Creates new table 400ac35ff17SAlexander V. Chernikov * 401ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 402ac35ff17SAlexander V. Chernikov * 403f1220db8SAlexander V. Chernikov * Returns 0 on success. 404f1220db8SAlexander V. Chernikov */ 405f1220db8SAlexander V. Chernikov static int 406ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 407f1220db8SAlexander V. Chernikov { 408ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 409ac35ff17SAlexander V. Chernikov int error; 410f1220db8SAlexander V. Chernikov 411ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 412ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 413ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 414ac35ff17SAlexander V. Chernikov 415ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 416ac35ff17SAlexander V. Chernikov 417ac35ff17SAlexander V. Chernikov return (error); 418ac35ff17SAlexander V. Chernikov } 419ac35ff17SAlexander V. Chernikov 420ac35ff17SAlexander V. Chernikov /* 421ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 422ac35ff17SAlexander V. Chernikov * Returns 0 on success. 423ac35ff17SAlexander V. Chernikov */ 424ac35ff17SAlexander V. Chernikov static int 425ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 426ac35ff17SAlexander V. Chernikov { 427ac35ff17SAlexander V. Chernikov 428ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 429f1220db8SAlexander V. Chernikov return (-1); 430f1220db8SAlexander V. Chernikov 431f1220db8SAlexander V. Chernikov return (0); 432f1220db8SAlexander V. Chernikov } 433f1220db8SAlexander V. Chernikov 434f1220db8SAlexander V. Chernikov /* 435ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 436f1220db8SAlexander V. Chernikov * Returns 0 on success. 437f1220db8SAlexander V. Chernikov */ 438f1220db8SAlexander V. Chernikov static int 439ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 440f1220db8SAlexander V. Chernikov { 441f1220db8SAlexander V. Chernikov 442ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 443f1220db8SAlexander V. Chernikov return (-1); 444f1220db8SAlexander V. Chernikov 445f1220db8SAlexander V. Chernikov return (0); 446f1220db8SAlexander V. Chernikov } 447f1220db8SAlexander V. Chernikov 448f1220db8SAlexander V. Chernikov /* 449ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 450f1220db8SAlexander V. Chernikov * it inside @i. 451f1220db8SAlexander V. Chernikov * Returns 0 on success. 452f1220db8SAlexander V. Chernikov */ 453f1220db8SAlexander V. Chernikov static int 454ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 455f1220db8SAlexander V. Chernikov { 456f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 457ac35ff17SAlexander V. Chernikov int error; 458f1220db8SAlexander V. Chernikov size_t sz; 459f1220db8SAlexander V. Chernikov 460f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 461f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 462ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 463f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 464f1220db8SAlexander V. Chernikov 465ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 466ac35ff17SAlexander V. Chernikov return (error); 467f1220db8SAlexander V. Chernikov 468f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 469ac35ff17SAlexander V. Chernikov return (EINVAL); 470f1220db8SAlexander V. Chernikov 471f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 472f1220db8SAlexander V. Chernikov 473f1220db8SAlexander V. Chernikov return (0); 474f1220db8SAlexander V. Chernikov } 475f1220db8SAlexander V. Chernikov 476*5f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 477*5f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 478*5f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 479*5f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 480*5f379342SAlexander V. Chernikov { NULL, 0 } 481*5f379342SAlexander V. Chernikov }; 482*5f379342SAlexander V. Chernikov 483*5f379342SAlexander V. Chernikov struct ta_cldata { 484*5f379342SAlexander V. Chernikov uint8_t taclass; 485*5f379342SAlexander V. Chernikov uint8_t spare4; 486*5f379342SAlexander V. Chernikov uint16_t itemsize; 487*5f379342SAlexander V. Chernikov uint16_t itemsize6; 488*5f379342SAlexander V. Chernikov uint32_t size; 489*5f379342SAlexander V. Chernikov uint32_t count; 490*5f379342SAlexander V. Chernikov }; 491*5f379342SAlexander V. Chernikov 492*5f379342SAlexander V. Chernikov /* 493*5f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 494*5f379342SAlexander V. Chernikov */ 495*5f379342SAlexander V. Chernikov static void 496*5f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 497*5f379342SAlexander V. Chernikov const char *af, const char *taclass) 498*5f379342SAlexander V. Chernikov { 499*5f379342SAlexander V. Chernikov 500*5f379342SAlexander V. Chernikov switch (d->taclass) { 501*5f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 502*5f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 503*5f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 504*5f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 505*5f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 506*5f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 507*5f379342SAlexander V. Chernikov else 508*5f379342SAlexander V. Chernikov printf(" size: %u items: %u " 509*5f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 510*5f379342SAlexander V. Chernikov d->size, d->count, 511*5f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 512*5f379342SAlexander V. Chernikov break; 513*5f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 514*5f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 515*5f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 516*5f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 517*5f379342SAlexander V. Chernikov d->count, d->itemsize); 518*5f379342SAlexander V. Chernikov else 519*5f379342SAlexander V. Chernikov printf(" items: %u " 520*5f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 521*5f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 522*5f379342SAlexander V. Chernikov break; 523*5f379342SAlexander V. Chernikov default: 524*5f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 525*5f379342SAlexander V. Chernikov } 526*5f379342SAlexander V. Chernikov } 527*5f379342SAlexander V. Chernikov 528f1220db8SAlexander V. Chernikov /* 529f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 530f1220db8SAlexander V. Chernikov */ 531f1220db8SAlexander V. Chernikov static int 532f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 533f1220db8SAlexander V. Chernikov { 534914bffb6SAlexander V. Chernikov const char *vtype; 535*5f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 536*5f379342SAlexander V. Chernikov int afdata, afitem; 537*5f379342SAlexander V. Chernikov struct ta_cldata d; 538914bffb6SAlexander V. Chernikov char ttype[64]; 539f1220db8SAlexander V. Chernikov 540914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 541ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 542ac35ff17SAlexander V. Chernikov vtype = "unknown"; 543ac35ff17SAlexander V. Chernikov 544914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 545914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 5469d099b4fSAlexander V. Chernikov printf(" valtype: %s, references: %u\n", vtype, i->refcnt); 5479d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 548f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 5494c0c07a5SAlexander V. Chernikov if (i->limit > 0) 5504c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 551f1220db8SAlexander V. Chernikov 552*5f379342SAlexander V. Chernikov /* Print algo-specific info if any */ 553*5f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 554*5f379342SAlexander V. Chernikov return (0); 555*5f379342SAlexander V. Chernikov tainfo = &i->ta_info; 556*5f379342SAlexander V. Chernikov 557*5f379342SAlexander V. Chernikov afdata = 0; 558*5f379342SAlexander V. Chernikov afitem = 0; 559*5f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 560*5f379342SAlexander V. Chernikov afdata = 1; 561*5f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 562*5f379342SAlexander V. Chernikov afitem = 1; 563*5f379342SAlexander V. Chernikov 564*5f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 565*5f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 566*5f379342SAlexander V. Chernikov d.size = tainfo->size4; 567*5f379342SAlexander V. Chernikov d.count = tainfo->count4; 568*5f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 569*5f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 570*5f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 571*5f379342SAlexander V. Chernikov else 572*5f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 573*5f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 574*5f379342SAlexander V. Chernikov vtype = "unknown"; 575*5f379342SAlexander V. Chernikov 576*5f379342SAlexander V. Chernikov if (afdata == 0) { 577*5f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 578*5f379342SAlexander V. Chernikov } else { 579*5f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 580*5f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 581*5f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 582*5f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 583*5f379342SAlexander V. Chernikov vtype = "unknown"; 584*5f379342SAlexander V. Chernikov d.size = tainfo->size6; 585*5f379342SAlexander V. Chernikov d.count = tainfo->count6; 586*5f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 587*5f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 588*5f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 589*5f379342SAlexander V. Chernikov } 590*5f379342SAlexander V. Chernikov 591f1220db8SAlexander V. Chernikov return (0); 592f1220db8SAlexander V. Chernikov } 593f1220db8SAlexander V. Chernikov 594f1220db8SAlexander V. Chernikov 595f1220db8SAlexander V. Chernikov /* 596f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 597f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 598f1220db8SAlexander V. Chernikov */ 599f1220db8SAlexander V. Chernikov 600f1220db8SAlexander V. Chernikov static int 601f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 602f1220db8SAlexander V. Chernikov { 603f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 60481d3153dSAlexander V. Chernikov int error; 605f1220db8SAlexander V. Chernikov 606ac35ff17SAlexander V. Chernikov if ((oh = calloc(1, i->size)) == NULL) 607f1220db8SAlexander V. Chernikov return (ENOMEM); 608f1220db8SAlexander V. Chernikov 60981d3153dSAlexander V. Chernikov if ((error = table_get_list(i, oh)) != 0) { 61081d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 61181d3153dSAlexander V. Chernikov return (error); 61281d3153dSAlexander V. Chernikov } 61381d3153dSAlexander V. Chernikov 614f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 615f1220db8SAlexander V. Chernikov 616f1220db8SAlexander V. Chernikov free(oh); 617f1220db8SAlexander V. Chernikov return (0); 618f1220db8SAlexander V. Chernikov } 619f1220db8SAlexander V. Chernikov 620f1220db8SAlexander V. Chernikov static int 621f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 622f1220db8SAlexander V. Chernikov { 623ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 624f1220db8SAlexander V. Chernikov 625ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 626ac35ff17SAlexander V. Chernikov 627ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 628ac35ff17SAlexander V. Chernikov 629ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 630f1220db8SAlexander V. Chernikov } 631f1220db8SAlexander V. Chernikov 632ac35ff17SAlexander V. Chernikov static int 633ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 634ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 635ac35ff17SAlexander V. Chernikov { 636db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 637db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 638ac35ff17SAlexander V. Chernikov int error; 639ac35ff17SAlexander V. Chernikov 640ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 641ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 642ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 643ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 644ac35ff17SAlexander V. Chernikov 645db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 646db785d31SAlexander V. Chernikov ctlv->count = 1; 647db785d31SAlexander V. Chernikov ctlv->head.length = sizeof(*ctlv) + sizeof(*tent); 648db785d31SAlexander V. Chernikov 649db785d31SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent)); 650db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 651ac35ff17SAlexander V. Chernikov if (update != 0) 65281d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 653ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 654ac35ff17SAlexander V. Chernikov 655ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 656ac35ff17SAlexander V. Chernikov 657ac35ff17SAlexander V. Chernikov return (error); 658ac35ff17SAlexander V. Chernikov } 659ac35ff17SAlexander V. Chernikov 660ac35ff17SAlexander V. Chernikov static void 661ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 662ac35ff17SAlexander V. Chernikov { 663ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 66481d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 665ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 6664c0c07a5SAlexander V. Chernikov int cmd, error; 6674c0c07a5SAlexander V. Chernikov char *texterr, *etxt; 668ac35ff17SAlexander V. Chernikov 669ac35ff17SAlexander V. Chernikov if (ac == 0) 670ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 671ac35ff17SAlexander V. Chernikov 672ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 673ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 674ac35ff17SAlexander V. Chernikov tent.idx = 1; 675ac35ff17SAlexander V. Chernikov 67681d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 677db785d31SAlexander V. Chernikov 678db785d31SAlexander V. Chernikov /* 679db785d31SAlexander V. Chernikov * compability layer: auto-create table if not exists 680db785d31SAlexander V. Chernikov */ 681db785d31SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 682db785d31SAlexander V. Chernikov xi.type = type; 683db785d31SAlexander V. Chernikov xi.vtype = vtype; 684db785d31SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); 685db785d31SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info non-existent " 686db785d31SAlexander V. Chernikov "table %s. (auto-created)\n", xi.tablename); 687db785d31SAlexander V. Chernikov table_do_create(oh, &xi); 688db785d31SAlexander V. Chernikov } 689db785d31SAlexander V. Chernikov 690ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 691ac35ff17SAlexander V. Chernikov ac--; av++; 692ac35ff17SAlexander V. Chernikov 693ac35ff17SAlexander V. Chernikov if (add != 0) { 694ac35ff17SAlexander V. Chernikov if (ac > 0) 695ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 696ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 6974c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 698ac35ff17SAlexander V. Chernikov } else { 699ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 7004c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 701ac35ff17SAlexander V. Chernikov } 702ac35ff17SAlexander V. Chernikov 7034c0c07a5SAlexander V. Chernikov if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0) 7044c0c07a5SAlexander V. Chernikov return; 7054c0c07a5SAlexander V. Chernikov 7064c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 7074c0c07a5SAlexander V. Chernikov switch (error) { 7084c0c07a5SAlexander V. Chernikov case EEXIST: 7094c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 7104c0c07a5SAlexander V. Chernikov break; 7114c0c07a5SAlexander V. Chernikov case EFBIG: 7124c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 7134c0c07a5SAlexander V. Chernikov break; 7144c0c07a5SAlexander V. Chernikov case ESRCH: 7154c0c07a5SAlexander V. Chernikov etxt = "table not found"; 7164c0c07a5SAlexander V. Chernikov break; 7174c0c07a5SAlexander V. Chernikov case ENOENT: 7184c0c07a5SAlexander V. Chernikov etxt = "record not found"; 7194c0c07a5SAlexander V. Chernikov break; 7204c0c07a5SAlexander V. Chernikov default: 7214c0c07a5SAlexander V. Chernikov etxt = strerror(error); 7224c0c07a5SAlexander V. Chernikov } 7234c0c07a5SAlexander V. Chernikov 7244c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 725ac35ff17SAlexander V. Chernikov } 726ac35ff17SAlexander V. Chernikov 72781d3153dSAlexander V. Chernikov static int 72881d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 72981d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 73081d3153dSAlexander V. Chernikov { 73181d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 73281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 73381d3153dSAlexander V. Chernikov uint8_t type, vtype; 73481d3153dSAlexander V. Chernikov int error; 73581d3153dSAlexander V. Chernikov size_t sz; 73681d3153dSAlexander V. Chernikov 73781d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 73881d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 73981d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 74081d3153dSAlexander V. Chernikov 74181d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 74281d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 74381d3153dSAlexander V. Chernikov tent->idx = 1; 74481d3153dSAlexander V. Chernikov 74581d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 74681d3153dSAlexander V. Chernikov oh->ntlv.type = type; 74781d3153dSAlexander V. Chernikov 74881d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 74981d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 75081d3153dSAlexander V. Chernikov return (error); 75181d3153dSAlexander V. Chernikov 75281d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 75381d3153dSAlexander V. Chernikov return (EINVAL); 75481d3153dSAlexander V. Chernikov 75581d3153dSAlexander V. Chernikov *xtent = *tent; 75681d3153dSAlexander V. Chernikov 75781d3153dSAlexander V. Chernikov return (0); 75881d3153dSAlexander V. Chernikov } 75981d3153dSAlexander V. Chernikov 76081d3153dSAlexander V. Chernikov static void 76181d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 76281d3153dSAlexander V. Chernikov { 76381d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 76481d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 765914bffb6SAlexander V. Chernikov char key[64]; 76681d3153dSAlexander V. Chernikov int error; 76781d3153dSAlexander V. Chernikov 76881d3153dSAlexander V. Chernikov if (ac == 0) 76981d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 77081d3153dSAlexander V. Chernikov 771914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 772914bffb6SAlexander V. Chernikov 773914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 77481d3153dSAlexander V. Chernikov 77581d3153dSAlexander V. Chernikov switch (error) { 77681d3153dSAlexander V. Chernikov case 0: 77781d3153dSAlexander V. Chernikov break; 77881d3153dSAlexander V. Chernikov case ESRCH: 77981d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 78081d3153dSAlexander V. Chernikov case ENOENT: 78181d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 78281d3153dSAlexander V. Chernikov case ENOTSUP: 78381d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 78481d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 78581d3153dSAlexander V. Chernikov default: 78681d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 78781d3153dSAlexander V. Chernikov } 78881d3153dSAlexander V. Chernikov 78981d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 79081d3153dSAlexander V. Chernikov } 791ac35ff17SAlexander V. Chernikov 792ac35ff17SAlexander V. Chernikov static void 793914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 794914bffb6SAlexander V. Chernikov uint8_t tflags) 795ac35ff17SAlexander V. Chernikov { 796914bffb6SAlexander V. Chernikov char *p, *pp; 797ac35ff17SAlexander V. Chernikov int mask, af; 798914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 799914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 800ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 801914bffb6SAlexander V. Chernikov uint16_t port; 802914bffb6SAlexander V. Chernikov struct protoent *pent; 803914bffb6SAlexander V. Chernikov struct servent *sent; 804ac35ff17SAlexander V. Chernikov int masklen; 805ac35ff17SAlexander V. Chernikov 806ac35ff17SAlexander V. Chernikov masklen = 0; 807ac35ff17SAlexander V. Chernikov af = 0; 808ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 809ac35ff17SAlexander V. Chernikov 810ac35ff17SAlexander V. Chernikov switch (type) { 811ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 812ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 813ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 814ac35ff17SAlexander V. Chernikov *p = '\0'; 815ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 816ac35ff17SAlexander V. Chernikov } 817ac35ff17SAlexander V. Chernikov 818ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 819ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 820ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 821ac35ff17SAlexander V. Chernikov p + 1); 822ac35ff17SAlexander V. Chernikov 823ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 824ac35ff17SAlexander V. Chernikov af = AF_INET; 825ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 826ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 827ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 828ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 829ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 830ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 831ac35ff17SAlexander V. Chernikov p + 1); 832ac35ff17SAlexander V. Chernikov 833ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 834ac35ff17SAlexander V. Chernikov af = AF_INET6; 835ac35ff17SAlexander V. Chernikov } else { 836ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 837ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 838ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 839ac35ff17SAlexander V. Chernikov 840ac35ff17SAlexander V. Chernikov masklen = 32; 841ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 842ac35ff17SAlexander V. Chernikov af = AF_INET; 843ac35ff17SAlexander V. Chernikov } 844ac35ff17SAlexander V. Chernikov break; 845ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 846ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 847ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 848ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 849ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 850ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 851ac35ff17SAlexander V. Chernikov break; 852b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 853ac35ff17SAlexander V. Chernikov /* Port or any other key */ 854ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 855ac35ff17SAlexander V. Chernikov if (*p != '\0') 856ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 857ac35ff17SAlexander V. Chernikov 858ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 859ac35ff17SAlexander V. Chernikov *pkey = key; 860ac35ff17SAlexander V. Chernikov masklen = 32; 861ac35ff17SAlexander V. Chernikov break; 862914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 863914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 864914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 865914bffb6SAlexander V. Chernikov af = 0; 866914bffb6SAlexander V. Chernikov 867914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 868914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 869914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 870914bffb6SAlexander V. Chernikov *p++ = '\0'; 871914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 872914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 873914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 874914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 875914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 876914bffb6SAlexander V. Chernikov af = AF_INET; 877914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 878914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 879914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 880914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 881914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 882914bffb6SAlexander V. Chernikov af = AF_INET6; 883914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 884914bffb6SAlexander V. Chernikov } 885914bffb6SAlexander V. Chernikov 886914bffb6SAlexander V. Chernikov arg = p; 887914bffb6SAlexander V. Chernikov } 888914bffb6SAlexander V. Chernikov 889914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 890914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 891914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 892914bffb6SAlexander V. Chernikov *p++ = '\0'; 893914bffb6SAlexander V. Chernikov 894914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 895914bffb6SAlexander V. Chernikov if (*pp != '\0') { 896914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 897914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 898914bffb6SAlexander V. Chernikov arg); 899914bffb6SAlexander V. Chernikov else 900914bffb6SAlexander V. Chernikov key = pent->p_proto; 901914bffb6SAlexander V. Chernikov } 902914bffb6SAlexander V. Chernikov 903914bffb6SAlexander V. Chernikov if (key > 255) 904914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 905914bffb6SAlexander V. Chernikov 906914bffb6SAlexander V. Chernikov tfe->proto = key; 907914bffb6SAlexander V. Chernikov 908914bffb6SAlexander V. Chernikov arg = p; 909914bffb6SAlexander V. Chernikov } 910914bffb6SAlexander V. Chernikov 911914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 912914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 913914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 914914bffb6SAlexander V. Chernikov *p++ = '\0'; 915914bffb6SAlexander V. Chernikov 916914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 917914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 918914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 919914bffb6SAlexander V. Chernikov arg); 920914bffb6SAlexander V. Chernikov else 921914bffb6SAlexander V. Chernikov key = sent->s_port; 922914bffb6SAlexander V. Chernikov } 923914bffb6SAlexander V. Chernikov 924914bffb6SAlexander V. Chernikov tfe->sport = port; 925914bffb6SAlexander V. Chernikov 926914bffb6SAlexander V. Chernikov arg = p; 927914bffb6SAlexander V. Chernikov } 928914bffb6SAlexander V. Chernikov 929914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 930914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 931914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 932914bffb6SAlexander V. Chernikov *p++ = '\0'; 933914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 934914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 935914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 936914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 937914bffb6SAlexander V. Chernikov "Inconsistent address family"); 938914bffb6SAlexander V. Chernikov af = AF_INET; 939914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 940914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 941914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 942914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 943914bffb6SAlexander V. Chernikov "Inconsistent address family"); 944914bffb6SAlexander V. Chernikov af = AF_INET6; 945914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 946914bffb6SAlexander V. Chernikov } 947914bffb6SAlexander V. Chernikov 948914bffb6SAlexander V. Chernikov arg = p; 949914bffb6SAlexander V. Chernikov } 950914bffb6SAlexander V. Chernikov 951914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 952914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 953914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 954914bffb6SAlexander V. Chernikov *p++ = '\0'; 955914bffb6SAlexander V. Chernikov 956914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 957914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 958914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 959914bffb6SAlexander V. Chernikov arg); 960914bffb6SAlexander V. Chernikov else 961914bffb6SAlexander V. Chernikov key = sent->s_port; 962914bffb6SAlexander V. Chernikov } 963914bffb6SAlexander V. Chernikov 964914bffb6SAlexander V. Chernikov tfe->dport = port; 965914bffb6SAlexander V. Chernikov 966914bffb6SAlexander V. Chernikov arg = p; 967914bffb6SAlexander V. Chernikov } 968914bffb6SAlexander V. Chernikov 969914bffb6SAlexander V. Chernikov tfe->af = af; 970914bffb6SAlexander V. Chernikov 971914bffb6SAlexander V. Chernikov break; 972914bffb6SAlexander V. Chernikov 973ac35ff17SAlexander V. Chernikov default: 974ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 975ac35ff17SAlexander V. Chernikov } 976ac35ff17SAlexander V. Chernikov 977ac35ff17SAlexander V. Chernikov tentry->subtype = af; 978ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 979ac35ff17SAlexander V. Chernikov } 980ac35ff17SAlexander V. Chernikov 981ac35ff17SAlexander V. Chernikov static void 982ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 98381d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 984ac35ff17SAlexander V. Chernikov { 985914bffb6SAlexander V. Chernikov uint8_t type, tflags, vtype; 986ac35ff17SAlexander V. Chernikov int error; 987db785d31SAlexander V. Chernikov char *del; 988ac35ff17SAlexander V. Chernikov 989ac35ff17SAlexander V. Chernikov type = 0; 990914bffb6SAlexander V. Chernikov tflags = 0; 991ac35ff17SAlexander V. Chernikov vtype = 0; 992ac35ff17SAlexander V. Chernikov 99381d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 99481d3153dSAlexander V. Chernikov 99581d3153dSAlexander V. Chernikov if (error == 0) { 99681d3153dSAlexander V. Chernikov /* Table found. */ 99781d3153dSAlexander V. Chernikov type = xi->type; 998914bffb6SAlexander V. Chernikov tflags = xi->tflags; 99981d3153dSAlexander V. Chernikov vtype = xi->vtype; 100081d3153dSAlexander V. Chernikov } else { 100181d3153dSAlexander V. Chernikov if (error != ESRCH) 100281d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 100381d3153dSAlexander V. Chernikov oh->ntlv.name); 1004ac35ff17SAlexander V. Chernikov /* 100581d3153dSAlexander V. Chernikov * Table does not exist. 100681d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 100781d3153dSAlexander V. Chernikov * before failing. 1008ac35ff17SAlexander V. Chernikov */ 1009db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 1010db785d31SAlexander V. Chernikov *del = '\0'; 1011ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 1012ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 1013ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 1014ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 1015ac35ff17SAlexander V. Chernikov /* 101681d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 101781d3153dSAlexander V. Chernikov * This should be changed for MFC. 1018ac35ff17SAlexander V. Chernikov */ 101981d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 102081d3153dSAlexander V. Chernikov } else { 102181d3153dSAlexander V. Chernikov /* Inknown key */ 102281d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1023db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 102481d3153dSAlexander V. Chernikov } 1025db785d31SAlexander V. Chernikov if (del != NULL) 1026db785d31SAlexander V. Chernikov *del = '/'; 1027ac35ff17SAlexander V. Chernikov } 1028ac35ff17SAlexander V. Chernikov 1029914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1030ac35ff17SAlexander V. Chernikov 1031ac35ff17SAlexander V. Chernikov *ptype = type; 1032ac35ff17SAlexander V. Chernikov *pvtype = vtype; 1033ac35ff17SAlexander V. Chernikov } 1034ac35ff17SAlexander V. Chernikov 1035ac35ff17SAlexander V. Chernikov static void 1036ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1037ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 1038ac35ff17SAlexander V. Chernikov { 1039ac35ff17SAlexander V. Chernikov int code; 1040ac35ff17SAlexander V. Chernikov char *p; 1041ac35ff17SAlexander V. Chernikov 1042ac35ff17SAlexander V. Chernikov switch (vtype) { 1043ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 1044ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1045ac35ff17SAlexander V. Chernikov if (*p != '\0') 1046ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 1047ac35ff17SAlexander V. Chernikov break; 1048ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 1049ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 1050ac35ff17SAlexander V. Chernikov break; 1051ac35ff17SAlexander V. Chernikov /* Try hostname */ 1052ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 1053ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 1054ac35ff17SAlexander V. Chernikov break; 1055ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1056ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 1057ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 1058ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 1059ac35ff17SAlexander V. Chernikov } else { 1060ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 1061ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 1062ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 1063ac35ff17SAlexander V. Chernikov } 1064ac35ff17SAlexander V. Chernikov tent->value = code; 1065ac35ff17SAlexander V. Chernikov break; 1066ac35ff17SAlexander V. Chernikov default: 1067ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 1068ac35ff17SAlexander V. Chernikov } 1069ac35ff17SAlexander V. Chernikov } 1070f1220db8SAlexander V. Chernikov 1071f1220db8SAlexander V. Chernikov /* 1072f1220db8SAlexander V. Chernikov * Compare table names. 1073f1220db8SAlexander V. Chernikov * Honor number comparison. 1074f1220db8SAlexander V. Chernikov */ 1075f1220db8SAlexander V. Chernikov static int 1076f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1077f1220db8SAlexander V. Chernikov { 1078f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1079f1220db8SAlexander V. Chernikov 1080f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1081f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1082f1220db8SAlexander V. Chernikov 108368394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1084f1220db8SAlexander V. Chernikov } 1085f1220db8SAlexander V. Chernikov 1086f1220db8SAlexander V. Chernikov /* 1087f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1088f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1089f1220db8SAlexander V. Chernikov * Returns 0 on success. 1090f1220db8SAlexander V. Chernikov */ 1091f1220db8SAlexander V. Chernikov static int 1092f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1093f1220db8SAlexander V. Chernikov { 1094f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 1095f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1096f1220db8SAlexander V. Chernikov size_t sz; 1097f1220db8SAlexander V. Chernikov int i, error; 1098f1220db8SAlexander V. Chernikov 1099f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 1100f1220db8SAlexander V. Chernikov sz = sizeof(req); 1101f1220db8SAlexander V. Chernikov 1102d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 1103f1220db8SAlexander V. Chernikov return (errno); 1104f1220db8SAlexander V. Chernikov 1105f1220db8SAlexander V. Chernikov sz = req.size; 1106f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1107f1220db8SAlexander V. Chernikov return (ENOMEM); 1108f1220db8SAlexander V. Chernikov 1109f1220db8SAlexander V. Chernikov olh->size = sz; 1110d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 1111f1220db8SAlexander V. Chernikov free(olh); 1112f1220db8SAlexander V. Chernikov return (errno); 1113f1220db8SAlexander V. Chernikov } 1114f1220db8SAlexander V. Chernikov 1115f1220db8SAlexander V. Chernikov if (sort != 0) 1116f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1117f1220db8SAlexander V. Chernikov 1118f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1119f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1120f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1121f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1122f1220db8SAlexander V. Chernikov } 1123f1220db8SAlexander V. Chernikov 1124f1220db8SAlexander V. Chernikov free(olh); 1125f1220db8SAlexander V. Chernikov 1126f1220db8SAlexander V. Chernikov return (0); 1127f1220db8SAlexander V. Chernikov } 1128f1220db8SAlexander V. Chernikov 1129f1220db8SAlexander V. Chernikov /* 1130f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1131d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 1132d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 1133f1220db8SAlexander V. Chernikov * 1134f1220db8SAlexander V. Chernikov * Returns 0 on success. 1135f1220db8SAlexander V. Chernikov */ 1136f1220db8SAlexander V. Chernikov static int 1137f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 1138f1220db8SAlexander V. Chernikov { 1139f1220db8SAlexander V. Chernikov size_t sz; 114081d3153dSAlexander V. Chernikov int error, c; 1141f1220db8SAlexander V. Chernikov 114281d3153dSAlexander V. Chernikov sz = 0; 114381d3153dSAlexander V. Chernikov for (c = 0; c < 3; c++) { 1144f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 114581d3153dSAlexander V. Chernikov if (sz < i->size) 1146f1220db8SAlexander V. Chernikov sz = i->size; 1147f1220db8SAlexander V. Chernikov 1148d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 114981d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1150d3a4f924SAlexander V. Chernikov 115181d3153dSAlexander V. Chernikov if (error != ENOMEM) 1152f1220db8SAlexander V. Chernikov return (errno); 115381d3153dSAlexander V. Chernikov } 1154f1220db8SAlexander V. Chernikov 115581d3153dSAlexander V. Chernikov return (ENOMEM); 1156f1220db8SAlexander V. Chernikov } 1157f1220db8SAlexander V. Chernikov 1158f1220db8SAlexander V. Chernikov /* 1159f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1160f1220db8SAlexander V. Chernikov */ 1161f1220db8SAlexander V. Chernikov static void 1162f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1163f1220db8SAlexander V. Chernikov { 116481d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 116581d3153dSAlexander V. Chernikov uint32_t count; 1166f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1167f1220db8SAlexander V. Chernikov 1168f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 116981d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1170f1220db8SAlexander V. Chernikov 1171f1220db8SAlexander V. Chernikov if (need_header) 1172f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1173f1220db8SAlexander V. Chernikov 1174f1220db8SAlexander V. Chernikov count = i->count; 1175f1220db8SAlexander V. Chernikov while (count > 0) { 117681d3153dSAlexander V. Chernikov table_show_entry(i, tent); 117781d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 117881d3153dSAlexander V. Chernikov count--; 117981d3153dSAlexander V. Chernikov } 118081d3153dSAlexander V. Chernikov } 118181d3153dSAlexander V. Chernikov 118281d3153dSAlexander V. Chernikov static void 118381d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 118481d3153dSAlexander V. Chernikov { 1185914bffb6SAlexander V. Chernikov char *comma, tbuf[128], pval[32]; 1186914bffb6SAlexander V. Chernikov void *paddr; 118781d3153dSAlexander V. Chernikov uint32_t tval; 1188914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 118981d3153dSAlexander V. Chernikov 119081d3153dSAlexander V. Chernikov tval = tent->value; 119181d3153dSAlexander V. Chernikov 1192914bffb6SAlexander V. Chernikov if (co.do_value_as_ip) { 1193914bffb6SAlexander V. Chernikov tval = htonl(tval); 1194914bffb6SAlexander V. Chernikov inet_ntop(AF_INET, &tval, pval, sizeof(pval)); 1195914bffb6SAlexander V. Chernikov } else 1196914bffb6SAlexander V. Chernikov snprintf(pval, sizeof(pval), "%u", tval); 1197914bffb6SAlexander V. Chernikov 1198f1220db8SAlexander V. Chernikov switch (i->type) { 1199f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1200f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 120181d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1202914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1203f1220db8SAlexander V. Chernikov break; 1204f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1205f1220db8SAlexander V. Chernikov /* Interface names */ 1206914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1207b23d5de9SAlexander V. Chernikov break; 1208b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1209b23d5de9SAlexander V. Chernikov /* numbers */ 1210914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1211b23d5de9SAlexander V. Chernikov break; 1212914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1213914bffb6SAlexander V. Chernikov /* flows */ 1214914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1215914bffb6SAlexander V. Chernikov comma = ""; 1216914bffb6SAlexander V. Chernikov 1217914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1218914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1219914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1220914bffb6SAlexander V. Chernikov else 1221914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1222914bffb6SAlexander V. Chernikov 1223914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1224914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1225914bffb6SAlexander V. Chernikov comma = ","; 1226914bffb6SAlexander V. Chernikov } 1227914bffb6SAlexander V. Chernikov 1228914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1229914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1230914bffb6SAlexander V. Chernikov comma = ","; 1231914bffb6SAlexander V. Chernikov } 1232914bffb6SAlexander V. Chernikov 1233914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1234914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1235914bffb6SAlexander V. Chernikov comma = ","; 1236914bffb6SAlexander V. Chernikov } 1237914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1238914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1239914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1240914bffb6SAlexander V. Chernikov else 1241914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1242914bffb6SAlexander V. Chernikov 1243914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1244914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1245914bffb6SAlexander V. Chernikov comma = ","; 1246914bffb6SAlexander V. Chernikov } 1247914bffb6SAlexander V. Chernikov 1248914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1249914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1250914bffb6SAlexander V. Chernikov comma = ","; 1251914bffb6SAlexander V. Chernikov } 1252914bffb6SAlexander V. Chernikov 1253914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1254f1220db8SAlexander V. Chernikov } 1255f1220db8SAlexander V. Chernikov } 1256f1220db8SAlexander V. Chernikov 12579d099b4fSAlexander V. Chernikov static int 12589d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 12599d099b4fSAlexander V. Chernikov { 12609d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 12619d099b4fSAlexander V. Chernikov size_t sz; 12629d099b4fSAlexander V. Chernikov int error; 12639d099b4fSAlexander V. Chernikov 12649d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 12659d099b4fSAlexander V. Chernikov sz = sizeof(req); 12669d099b4fSAlexander V. Chernikov 12679d099b4fSAlexander V. Chernikov error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); 12689d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 12699d099b4fSAlexander V. Chernikov return (error); 12709d099b4fSAlexander V. Chernikov 12719d099b4fSAlexander V. Chernikov sz = req.size; 12729d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 12739d099b4fSAlexander V. Chernikov return (ENOMEM); 12749d099b4fSAlexander V. Chernikov 12759d099b4fSAlexander V. Chernikov olh->size = sz; 12769d099b4fSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { 12779d099b4fSAlexander V. Chernikov free(olh); 12789d099b4fSAlexander V. Chernikov return (error); 12799d099b4fSAlexander V. Chernikov } 12809d099b4fSAlexander V. Chernikov 12819d099b4fSAlexander V. Chernikov *polh = olh; 12829d099b4fSAlexander V. Chernikov return (0); 12839d099b4fSAlexander V. Chernikov } 12849d099b4fSAlexander V. Chernikov 12859d099b4fSAlexander V. Chernikov void 12869d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 12879d099b4fSAlexander V. Chernikov { 12889d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 12899d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 12909d099b4fSAlexander V. Chernikov int error, i; 12919d099b4fSAlexander V. Chernikov const char *atype; 12929d099b4fSAlexander V. Chernikov 12939d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 12949d099b4fSAlexander V. Chernikov if (error != 0) 12959d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 12969d099b4fSAlexander V. Chernikov 12979d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 12989d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 12999d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 13009d099b4fSAlexander V. Chernikov atype = "unknown"; 13018ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 13028ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 13039d099b4fSAlexander V. Chernikov 13049d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 13059d099b4fSAlexander V. Chernikov } 13069d099b4fSAlexander V. Chernikov 13079d099b4fSAlexander V. Chernikov free(olh); 13089d099b4fSAlexander V. Chernikov } 13099d099b4fSAlexander V. Chernikov 13106c2997ffSAlexander V. Chernikov int 13116c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 13126c2997ffSAlexander V. Chernikov { 13136c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 13146c2997ffSAlexander V. Chernikov 13156c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 13166c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 13176c2997ffSAlexander V. Chernikov 13186c2997ffSAlexander V. Chernikov if (a->set < b->set) 13196c2997ffSAlexander V. Chernikov return (-1); 13206c2997ffSAlexander V. Chernikov else if (a->set > b->set) 13216c2997ffSAlexander V. Chernikov return (1); 13226c2997ffSAlexander V. Chernikov 13236c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 13246c2997ffSAlexander V. Chernikov return (-1); 13256c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 13266c2997ffSAlexander V. Chernikov return (1); 13276c2997ffSAlexander V. Chernikov 13286c2997ffSAlexander V. Chernikov return (0); 13296c2997ffSAlexander V. Chernikov } 1330563b5ab1SAlexander V. Chernikov 1331563b5ab1SAlexander V. Chernikov int 13326c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1333563b5ab1SAlexander V. Chernikov { 1334563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1335563b5ab1SAlexander V. Chernikov uint16_t key; 1336563b5ab1SAlexander V. Chernikov 1337563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1338563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1339563b5ab1SAlexander V. Chernikov 1340563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1341563b5ab1SAlexander V. Chernikov return (-1); 1342563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1343563b5ab1SAlexander V. Chernikov return (1); 1344563b5ab1SAlexander V. Chernikov 1345563b5ab1SAlexander V. Chernikov return (0); 1346563b5ab1SAlexander V. Chernikov } 1347563b5ab1SAlexander V. Chernikov 1348563b5ab1SAlexander V. Chernikov /* 1349563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1350563b5ab1SAlexander V. Chernikov * Uses the following facts: 1351563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1352563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1353563b5ab1SAlexander V. Chernikov * 1354563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1355563b5ab1SAlexander V. Chernikov */ 1356563b5ab1SAlexander V. Chernikov char * 1357563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1358563b5ab1SAlexander V. Chernikov { 1359563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1360563b5ab1SAlexander V. Chernikov 1361563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 13626c2997ffSAlexander V. Chernikov compare_kntlv); 1363563b5ab1SAlexander V. Chernikov 1364563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1365563b5ab1SAlexander V. Chernikov return (ntlv->name); 1366563b5ab1SAlexander V. Chernikov 1367563b5ab1SAlexander V. Chernikov return (NULL); 1368563b5ab1SAlexander V. Chernikov } 1369563b5ab1SAlexander V. Chernikov 13706c2997ffSAlexander V. Chernikov void 13716c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 13726c2997ffSAlexander V. Chernikov { 13736c2997ffSAlexander V. Chernikov 13746c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 13756c2997ffSAlexander V. Chernikov } 13766c2997ffSAlexander V. Chernikov 13776c2997ffSAlexander V. Chernikov int 13786c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 13796c2997ffSAlexander V. Chernikov { 13806c2997ffSAlexander V. Chernikov int c, i, l; 13816c2997ffSAlexander V. Chernikov 13826c2997ffSAlexander V. Chernikov /* 13836c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 13846c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 1385ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 13866c2997ffSAlexander V. Chernikov */ 13876c2997ffSAlexander V. Chernikov l = strlen(tablename); 13886c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 13896c2997ffSAlexander V. Chernikov return (EINVAL); 13906c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 13916c2997ffSAlexander V. Chernikov c = tablename[i]; 13926c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 13936c2997ffSAlexander V. Chernikov c == '-' || c == '.') 13946c2997ffSAlexander V. Chernikov continue; 13956c2997ffSAlexander V. Chernikov return (EINVAL); 13966c2997ffSAlexander V. Chernikov } 13976c2997ffSAlexander V. Chernikov 1398ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1399ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1400ac35ff17SAlexander V. Chernikov return (EINVAL); 1401ac35ff17SAlexander V. Chernikov 14026c2997ffSAlexander V. Chernikov return (0); 14036c2997ffSAlexander V. Chernikov } 14046c2997ffSAlexander V. Chernikov 1405