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 }, 104358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 105ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 10681d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 107ac35ff17SAlexander V. Chernikov { NULL, 0 } 108ac35ff17SAlexander V. Chernikov }; 109ac35ff17SAlexander V. Chernikov 110f1220db8SAlexander V. Chernikov static int 111f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 112f1220db8SAlexander V. Chernikov { 113f1220db8SAlexander V. Chernikov struct hostent *he; 114f1220db8SAlexander V. Chernikov 115f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 116f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 117f1220db8SAlexander V. Chernikov return(-1); 118f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 119f1220db8SAlexander V. Chernikov } 120f1220db8SAlexander V. Chernikov return(0); 121f1220db8SAlexander V. Chernikov } 122f1220db8SAlexander V. Chernikov 123f1220db8SAlexander V. Chernikov /* 124f1220db8SAlexander V. Chernikov * This one handles all table-related commands 125ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 126ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 127ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 128ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 129ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 130ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 131ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 132f1220db8SAlexander V. Chernikov */ 133f1220db8SAlexander V. Chernikov void 134f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 135f1220db8SAlexander V. Chernikov { 136ac35ff17SAlexander V. Chernikov int do_add, is_all; 137ac35ff17SAlexander V. Chernikov int error, tcmd; 138ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 139ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 140f1220db8SAlexander V. Chernikov char *tablename; 141ac35ff17SAlexander V. Chernikov uint32_t set; 142358b9d09SAlexander V. Chernikov void *arg; 143f1220db8SAlexander V. Chernikov 144ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 145ac35ff17SAlexander V. Chernikov is_all = 0; 146ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 147ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 148ac35ff17SAlexander V. Chernikov else 149ac35ff17SAlexander V. Chernikov set = 0; 150f1220db8SAlexander V. Chernikov 151f1220db8SAlexander V. Chernikov ac--; av++; 1529d099b4fSAlexander V. Chernikov NEED1("table needs name"); 153f1220db8SAlexander V. Chernikov tablename = *av; 154f1220db8SAlexander V. Chernikov 155ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 156ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 157ac35ff17SAlexander V. Chernikov oh.idx = 1; 158ac35ff17SAlexander V. Chernikov } else { 159ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 160ac35ff17SAlexander V. Chernikov is_all = 1; 161ac35ff17SAlexander V. Chernikov else 162ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 163ac35ff17SAlexander V. Chernikov } 164ac35ff17SAlexander V. Chernikov ac--; av++; 1659d099b4fSAlexander V. Chernikov NEED1("table needs command"); 166ac35ff17SAlexander V. Chernikov 167ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 168ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 169ac35ff17SAlexander V. Chernikov 170ac35ff17SAlexander V. Chernikov switch (tcmd) { 171ac35ff17SAlexander V. Chernikov case TOK_LIST: 172ac35ff17SAlexander V. Chernikov case TOK_INFO: 173358b9d09SAlexander V. Chernikov case TOK_DETAIL: 174ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 175ac35ff17SAlexander V. Chernikov break; 176ac35ff17SAlexander V. Chernikov default: 177ac35ff17SAlexander V. Chernikov if (is_all != 0) 178ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 179ac35ff17SAlexander V. Chernikov } 180ac35ff17SAlexander V. Chernikov 181ac35ff17SAlexander V. Chernikov switch (tcmd) { 182ac35ff17SAlexander V. Chernikov case TOK_ADD: 183ac35ff17SAlexander V. Chernikov case TOK_DEL: 184f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 185f1220db8SAlexander V. Chernikov ac--; av++; 186ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 187ac35ff17SAlexander V. Chernikov break; 188ac35ff17SAlexander V. Chernikov case TOK_CREATE: 189f1220db8SAlexander V. Chernikov ac--; av++; 190ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 191ac35ff17SAlexander V. Chernikov break; 192ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 193ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 194ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 195ac35ff17SAlexander V. Chernikov break; 196ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 197f1220db8SAlexander V. Chernikov if (is_all == 0) { 198ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 199f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 200f1220db8SAlexander V. Chernikov tablename); 201f1220db8SAlexander V. Chernikov } else { 202ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 203f1220db8SAlexander V. Chernikov if (error != 0) 204f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 205f1220db8SAlexander V. Chernikov } 206ac35ff17SAlexander V. Chernikov break; 207358b9d09SAlexander V. Chernikov case TOK_DETAIL: 208ac35ff17SAlexander V. Chernikov case TOK_INFO: 209358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 210f1220db8SAlexander V. Chernikov if (is_all == 0) { 211ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 212f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 213358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 214f1220db8SAlexander V. Chernikov } else { 215358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 216f1220db8SAlexander V. Chernikov if (error != 0) 217f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 218f1220db8SAlexander V. Chernikov } 219ac35ff17SAlexander V. Chernikov break; 220ac35ff17SAlexander V. Chernikov case TOK_LIST: 221ac35ff17SAlexander V. Chernikov if (is_all == 0) { 222ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 223ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 224ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 225ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 226f1220db8SAlexander V. Chernikov } else { 227ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 228ac35ff17SAlexander V. Chernikov if (error != 0) 229ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 230f1220db8SAlexander V. Chernikov } 231ac35ff17SAlexander V. Chernikov break; 23281d3153dSAlexander V. Chernikov case TOK_LOOKUP: 23381d3153dSAlexander V. Chernikov ac--; av++; 23481d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 23581d3153dSAlexander V. Chernikov break; 236f1220db8SAlexander V. Chernikov } 237f1220db8SAlexander V. Chernikov } 238f1220db8SAlexander V. Chernikov 239f1220db8SAlexander V. Chernikov static void 240ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 241f1220db8SAlexander V. Chernikov { 242f1220db8SAlexander V. Chernikov 243563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 244f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 245f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 246ac35ff17SAlexander V. Chernikov ntlv->set = set; 247f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 248f1220db8SAlexander V. Chernikov } 249f1220db8SAlexander V. Chernikov 250f1220db8SAlexander V. Chernikov static void 251f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 252f1220db8SAlexander V. Chernikov { 253f1220db8SAlexander V. Chernikov 254f1220db8SAlexander V. Chernikov oh->idx = 1; 25581d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 256ac35ff17SAlexander V. Chernikov } 257ac35ff17SAlexander V. Chernikov 258ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 259ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 260ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 261ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 2624c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 263ac35ff17SAlexander V. Chernikov { NULL, 0 } 264ac35ff17SAlexander V. Chernikov }; 265ac35ff17SAlexander V. Chernikov 266914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 267914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 268914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 269914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 270914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 271914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 272914bffb6SAlexander V. Chernikov { NULL, 0 } 273914bffb6SAlexander V. Chernikov }; 274914bffb6SAlexander V. Chernikov 275914bffb6SAlexander V. Chernikov int 276914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 277914bffb6SAlexander V. Chernikov { 278914bffb6SAlexander V. Chernikov uint8_t fset, fclear; 279914bffb6SAlexander V. Chernikov 280914bffb6SAlexander V. Chernikov /* Parse type options */ 281914bffb6SAlexander V. Chernikov switch(ttype) { 282914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 283914bffb6SAlexander V. Chernikov fset = fclear = 0; 284914bffb6SAlexander V. Chernikov fill_flags(flowtypecmds, p, &fset, 285914bffb6SAlexander V. Chernikov &fclear); 286914bffb6SAlexander V. Chernikov *tflags = fset; 287914bffb6SAlexander V. Chernikov break; 288914bffb6SAlexander V. Chernikov default: 289914bffb6SAlexander V. Chernikov return (EX_USAGE); 290914bffb6SAlexander V. Chernikov } 291914bffb6SAlexander V. Chernikov 292914bffb6SAlexander V. Chernikov return (0); 293914bffb6SAlexander V. Chernikov } 294914bffb6SAlexander V. Chernikov 295914bffb6SAlexander V. Chernikov void 296914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 297914bffb6SAlexander V. Chernikov { 298914bffb6SAlexander V. Chernikov const char *tname; 299914bffb6SAlexander V. Chernikov int l; 300914bffb6SAlexander V. Chernikov 301914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 302914bffb6SAlexander V. Chernikov tname = "unknown"; 303914bffb6SAlexander V. Chernikov 304914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 305914bffb6SAlexander V. Chernikov tbuf += l; 306914bffb6SAlexander V. Chernikov size -= l; 307914bffb6SAlexander V. Chernikov 308914bffb6SAlexander V. Chernikov switch(type) { 309914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 310914bffb6SAlexander V. Chernikov if (tflags != 0) { 311914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 312914bffb6SAlexander V. Chernikov l--; 313914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 314914bffb6SAlexander V. Chernikov } 315914bffb6SAlexander V. Chernikov break; 316914bffb6SAlexander V. Chernikov } 317914bffb6SAlexander V. Chernikov } 318914bffb6SAlexander V. Chernikov 319ac35ff17SAlexander V. Chernikov /* 320ac35ff17SAlexander V. Chernikov * Creates new table 321ac35ff17SAlexander V. Chernikov * 322ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 323ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 324ac35ff17SAlexander V. Chernikov * [ algo algoname ] 325ac35ff17SAlexander V. Chernikov * 326ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 327ac35ff17SAlexander V. Chernikov */ 328ac35ff17SAlexander V. Chernikov static void 329ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 330ac35ff17SAlexander V. Chernikov { 331ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 332ac35ff17SAlexander V. Chernikov int error, tcmd, val; 333ac35ff17SAlexander V. Chernikov size_t sz; 334914bffb6SAlexander V. Chernikov char *p; 335ac35ff17SAlexander V. Chernikov char tbuf[128]; 336ac35ff17SAlexander V. Chernikov 337ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 338ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 339ac35ff17SAlexander V. Chernikov 340ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 341ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 342ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 343ac35ff17SAlexander V. Chernikov 344ac35ff17SAlexander V. Chernikov while (ac > 0) { 345ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 346ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 347ac35ff17SAlexander V. Chernikov ac--; av++; 348ac35ff17SAlexander V. Chernikov 349ac35ff17SAlexander V. Chernikov switch (tcmd) { 3504c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 3514c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 3524c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 3534c0c07a5SAlexander V. Chernikov ac--; av++; 3544c0c07a5SAlexander V. Chernikov break; 355ac35ff17SAlexander V. Chernikov case TOK_TYPE: 356ac35ff17SAlexander V. Chernikov NEED1("table type required"); 357914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 358914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 359914bffb6SAlexander V. Chernikov *p++ = '\0'; 360ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 361914bffb6SAlexander V. Chernikov if (val == -1) { 362914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 363914bffb6SAlexander V. Chernikov ", "); 364914bffb6SAlexander V. Chernikov errx(EX_USAGE, 365914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 366ac35ff17SAlexander V. Chernikov *av, tbuf); 367914bffb6SAlexander V. Chernikov } 368914bffb6SAlexander V. Chernikov xi.type = val; 369914bffb6SAlexander V. Chernikov if (p != NULL) { 370914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 371914bffb6SAlexander V. Chernikov if (error != 0) 372914bffb6SAlexander V. Chernikov errx(EX_USAGE, 373914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 374914bffb6SAlexander V. Chernikov } 375914bffb6SAlexander V. Chernikov ac--; av++; 376ac35ff17SAlexander V. Chernikov break; 377ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 378ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 379ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 380ac35ff17SAlexander V. Chernikov if (val != -1) { 381ac35ff17SAlexander V. Chernikov xi.vtype = val; 382ac35ff17SAlexander V. Chernikov ac--; av++; 383ac35ff17SAlexander V. Chernikov break; 384ac35ff17SAlexander V. Chernikov } 385ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 386ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 387ac35ff17SAlexander V. Chernikov *av, tbuf); 388ac35ff17SAlexander V. Chernikov break; 389ac35ff17SAlexander V. Chernikov case TOK_ALGO: 390ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 391ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 392ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 393ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 394ac35ff17SAlexander V. Chernikov ac--; av++; 395ac35ff17SAlexander V. Chernikov break; 396ac35ff17SAlexander V. Chernikov } 397ac35ff17SAlexander V. Chernikov } 398ac35ff17SAlexander V. Chernikov 399ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 400ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 401f1220db8SAlexander V. Chernikov } 402f1220db8SAlexander V. Chernikov 403f1220db8SAlexander V. Chernikov /* 404ac35ff17SAlexander V. Chernikov * Creates new table 405ac35ff17SAlexander V. Chernikov * 406ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 407ac35ff17SAlexander V. Chernikov * 408f1220db8SAlexander V. Chernikov * Returns 0 on success. 409f1220db8SAlexander V. Chernikov */ 410f1220db8SAlexander V. Chernikov static int 411ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 412f1220db8SAlexander V. Chernikov { 413ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 414ac35ff17SAlexander V. Chernikov int error; 415f1220db8SAlexander V. Chernikov 416ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 417ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 418ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 419ac35ff17SAlexander V. Chernikov 420ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 421ac35ff17SAlexander V. Chernikov 422ac35ff17SAlexander V. Chernikov return (error); 423ac35ff17SAlexander V. Chernikov } 424ac35ff17SAlexander V. Chernikov 425ac35ff17SAlexander V. Chernikov /* 426ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 427ac35ff17SAlexander V. Chernikov * Returns 0 on success. 428ac35ff17SAlexander V. Chernikov */ 429ac35ff17SAlexander V. Chernikov static int 430ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 431ac35ff17SAlexander V. Chernikov { 432ac35ff17SAlexander V. Chernikov 433ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 434f1220db8SAlexander V. Chernikov return (-1); 435f1220db8SAlexander V. Chernikov 436f1220db8SAlexander V. Chernikov return (0); 437f1220db8SAlexander V. Chernikov } 438f1220db8SAlexander V. Chernikov 439f1220db8SAlexander V. Chernikov /* 440ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 441f1220db8SAlexander V. Chernikov * Returns 0 on success. 442f1220db8SAlexander V. Chernikov */ 443f1220db8SAlexander V. Chernikov static int 444ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 445f1220db8SAlexander V. Chernikov { 446f1220db8SAlexander V. Chernikov 447ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 448f1220db8SAlexander V. Chernikov return (-1); 449f1220db8SAlexander V. Chernikov 450f1220db8SAlexander V. Chernikov return (0); 451f1220db8SAlexander V. Chernikov } 452f1220db8SAlexander V. Chernikov 453f1220db8SAlexander V. Chernikov /* 454ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 455f1220db8SAlexander V. Chernikov * it inside @i. 456f1220db8SAlexander V. Chernikov * Returns 0 on success. 457f1220db8SAlexander V. Chernikov */ 458f1220db8SAlexander V. Chernikov static int 459ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 460f1220db8SAlexander V. Chernikov { 461f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 462ac35ff17SAlexander V. Chernikov int error; 463f1220db8SAlexander V. Chernikov size_t sz; 464f1220db8SAlexander V. Chernikov 465f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 466f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 467ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 468f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 469f1220db8SAlexander V. Chernikov 470ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 471ac35ff17SAlexander V. Chernikov return (error); 472f1220db8SAlexander V. Chernikov 473f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 474ac35ff17SAlexander V. Chernikov return (EINVAL); 475f1220db8SAlexander V. Chernikov 476f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 477f1220db8SAlexander V. Chernikov 478f1220db8SAlexander V. Chernikov return (0); 479f1220db8SAlexander V. Chernikov } 480f1220db8SAlexander V. Chernikov 4815f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 4825f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 4835f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 4845f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 4855f379342SAlexander V. Chernikov { NULL, 0 } 4865f379342SAlexander V. Chernikov }; 4875f379342SAlexander V. Chernikov 4885f379342SAlexander V. Chernikov struct ta_cldata { 4895f379342SAlexander V. Chernikov uint8_t taclass; 4905f379342SAlexander V. Chernikov uint8_t spare4; 4915f379342SAlexander V. Chernikov uint16_t itemsize; 4925f379342SAlexander V. Chernikov uint16_t itemsize6; 4935f379342SAlexander V. Chernikov uint32_t size; 4945f379342SAlexander V. Chernikov uint32_t count; 4955f379342SAlexander V. Chernikov }; 4965f379342SAlexander V. Chernikov 4975f379342SAlexander V. Chernikov /* 4985f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 4995f379342SAlexander V. Chernikov */ 5005f379342SAlexander V. Chernikov static void 5015f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 5025f379342SAlexander V. Chernikov const char *af, const char *taclass) 5035f379342SAlexander V. Chernikov { 5045f379342SAlexander V. Chernikov 5055f379342SAlexander V. Chernikov switch (d->taclass) { 5065f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 5075f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 5085f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 5095f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 5105f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 5115f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 5125f379342SAlexander V. Chernikov else 5135f379342SAlexander V. Chernikov printf(" size: %u items: %u " 5145f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 5155f379342SAlexander V. Chernikov d->size, d->count, 5165f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 5175f379342SAlexander V. Chernikov break; 5185f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 5195f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 5205f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 5215f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 5225f379342SAlexander V. Chernikov d->count, d->itemsize); 5235f379342SAlexander V. Chernikov else 5245f379342SAlexander V. Chernikov printf(" items: %u " 5255f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 5265f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 5275f379342SAlexander V. Chernikov break; 5285f379342SAlexander V. Chernikov default: 5295f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 5305f379342SAlexander V. Chernikov } 5315f379342SAlexander V. Chernikov } 5325f379342SAlexander V. Chernikov 533f1220db8SAlexander V. Chernikov /* 534f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 535f1220db8SAlexander V. Chernikov */ 536f1220db8SAlexander V. Chernikov static int 537f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 538f1220db8SAlexander V. Chernikov { 539914bffb6SAlexander V. Chernikov const char *vtype; 5405f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 5415f379342SAlexander V. Chernikov int afdata, afitem; 5425f379342SAlexander V. Chernikov struct ta_cldata d; 543914bffb6SAlexander V. Chernikov char ttype[64]; 544f1220db8SAlexander V. Chernikov 545914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 546ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 547ac35ff17SAlexander V. Chernikov vtype = "unknown"; 548ac35ff17SAlexander V. Chernikov 549914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 550914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 5519d099b4fSAlexander V. Chernikov printf(" valtype: %s, references: %u\n", vtype, i->refcnt); 5529d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 553f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 5544c0c07a5SAlexander V. Chernikov if (i->limit > 0) 5554c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 556f1220db8SAlexander V. Chernikov 557358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 558358b9d09SAlexander V. Chernikov if (arg == NULL) 559358b9d09SAlexander V. Chernikov return (0); 560358b9d09SAlexander V. Chernikov 5615f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 5625f379342SAlexander V. Chernikov return (0); 5635f379342SAlexander V. Chernikov tainfo = &i->ta_info; 5645f379342SAlexander V. Chernikov 5655f379342SAlexander V. Chernikov afdata = 0; 5665f379342SAlexander V. Chernikov afitem = 0; 5675f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 5685f379342SAlexander V. Chernikov afdata = 1; 5695f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 5705f379342SAlexander V. Chernikov afitem = 1; 5715f379342SAlexander V. Chernikov 5725f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 5735f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 5745f379342SAlexander V. Chernikov d.size = tainfo->size4; 5755f379342SAlexander V. Chernikov d.count = tainfo->count4; 5765f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 5775f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 5785f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 5795f379342SAlexander V. Chernikov else 5805f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 5815f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 5825f379342SAlexander V. Chernikov vtype = "unknown"; 5835f379342SAlexander V. Chernikov 5845f379342SAlexander V. Chernikov if (afdata == 0) { 5855f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 5865f379342SAlexander V. Chernikov } else { 5875f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 5885f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 5895f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 5905f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 5915f379342SAlexander V. Chernikov vtype = "unknown"; 5925f379342SAlexander V. Chernikov d.size = tainfo->size6; 5935f379342SAlexander V. Chernikov d.count = tainfo->count6; 5945f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 5955f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 5965f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 5975f379342SAlexander V. Chernikov } 5985f379342SAlexander V. Chernikov 599f1220db8SAlexander V. Chernikov return (0); 600f1220db8SAlexander V. Chernikov } 601f1220db8SAlexander V. Chernikov 602f1220db8SAlexander V. Chernikov 603f1220db8SAlexander V. Chernikov /* 604f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 605f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 606f1220db8SAlexander V. Chernikov */ 607f1220db8SAlexander V. Chernikov 608f1220db8SAlexander V. Chernikov static int 609f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 610f1220db8SAlexander V. Chernikov { 611f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 61281d3153dSAlexander V. Chernikov int error; 613f1220db8SAlexander V. Chernikov 614ac35ff17SAlexander V. Chernikov if ((oh = calloc(1, i->size)) == NULL) 615f1220db8SAlexander V. Chernikov return (ENOMEM); 616f1220db8SAlexander V. Chernikov 61781d3153dSAlexander V. Chernikov if ((error = table_get_list(i, oh)) != 0) { 61881d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 61981d3153dSAlexander V. Chernikov return (error); 62081d3153dSAlexander V. Chernikov } 62181d3153dSAlexander V. Chernikov 622f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 623f1220db8SAlexander V. Chernikov 624f1220db8SAlexander V. Chernikov free(oh); 625f1220db8SAlexander V. Chernikov return (0); 626f1220db8SAlexander V. Chernikov } 627f1220db8SAlexander V. Chernikov 628f1220db8SAlexander V. Chernikov static int 629f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 630f1220db8SAlexander V. Chernikov { 631ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 632f1220db8SAlexander V. Chernikov 633ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 634ac35ff17SAlexander V. Chernikov 635ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 636ac35ff17SAlexander V. Chernikov 637ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 638f1220db8SAlexander V. Chernikov } 639f1220db8SAlexander V. Chernikov 640ac35ff17SAlexander V. Chernikov static int 641ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 642ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 643ac35ff17SAlexander V. Chernikov { 644db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 645db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 646ac35ff17SAlexander V. Chernikov int error; 647ac35ff17SAlexander V. Chernikov 648ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 649ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 650ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 651ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 652ac35ff17SAlexander V. Chernikov 653db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 654db785d31SAlexander V. Chernikov ctlv->count = 1; 655db785d31SAlexander V. Chernikov ctlv->head.length = sizeof(*ctlv) + sizeof(*tent); 656db785d31SAlexander V. Chernikov 657db785d31SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent)); 658db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 659ac35ff17SAlexander V. Chernikov if (update != 0) 66081d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 661ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 662ac35ff17SAlexander V. Chernikov 663ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 664ac35ff17SAlexander V. Chernikov 665ac35ff17SAlexander V. Chernikov return (error); 666ac35ff17SAlexander V. Chernikov } 667ac35ff17SAlexander V. Chernikov 668ac35ff17SAlexander V. Chernikov static void 669ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 670ac35ff17SAlexander V. Chernikov { 671ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 67281d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 673ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 6744c0c07a5SAlexander V. Chernikov int cmd, error; 6754c0c07a5SAlexander V. Chernikov char *texterr, *etxt; 676ac35ff17SAlexander V. Chernikov 677ac35ff17SAlexander V. Chernikov if (ac == 0) 678ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 679ac35ff17SAlexander V. Chernikov 680ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 681ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 682ac35ff17SAlexander V. Chernikov tent.idx = 1; 683ac35ff17SAlexander V. Chernikov 68481d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 685db785d31SAlexander V. Chernikov 686db785d31SAlexander V. Chernikov /* 687db785d31SAlexander V. Chernikov * compability layer: auto-create table if not exists 688db785d31SAlexander V. Chernikov */ 689db785d31SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 690db785d31SAlexander V. Chernikov xi.type = type; 691db785d31SAlexander V. Chernikov xi.vtype = vtype; 692db785d31SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); 693db785d31SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info non-existent " 694db785d31SAlexander V. Chernikov "table %s. (auto-created)\n", xi.tablename); 695db785d31SAlexander V. Chernikov table_do_create(oh, &xi); 696db785d31SAlexander V. Chernikov } 697db785d31SAlexander V. Chernikov 698ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 699ac35ff17SAlexander V. Chernikov ac--; av++; 700ac35ff17SAlexander V. Chernikov 701ac35ff17SAlexander V. Chernikov if (add != 0) { 702ac35ff17SAlexander V. Chernikov if (ac > 0) 703ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 704ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 7054c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 706ac35ff17SAlexander V. Chernikov } else { 707ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 7084c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 709ac35ff17SAlexander V. Chernikov } 710ac35ff17SAlexander V. Chernikov 7114c0c07a5SAlexander V. Chernikov if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0) 7124c0c07a5SAlexander V. Chernikov return; 7134c0c07a5SAlexander V. Chernikov 7144c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 7154c0c07a5SAlexander V. Chernikov switch (error) { 7164c0c07a5SAlexander V. Chernikov case EEXIST: 7174c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 7184c0c07a5SAlexander V. Chernikov break; 7194c0c07a5SAlexander V. Chernikov case EFBIG: 7204c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 7214c0c07a5SAlexander V. Chernikov break; 7224c0c07a5SAlexander V. Chernikov case ESRCH: 7234c0c07a5SAlexander V. Chernikov etxt = "table not found"; 7244c0c07a5SAlexander V. Chernikov break; 7254c0c07a5SAlexander V. Chernikov case ENOENT: 7264c0c07a5SAlexander V. Chernikov etxt = "record not found"; 7274c0c07a5SAlexander V. Chernikov break; 7284c0c07a5SAlexander V. Chernikov default: 7294c0c07a5SAlexander V. Chernikov etxt = strerror(error); 7304c0c07a5SAlexander V. Chernikov } 7314c0c07a5SAlexander V. Chernikov 7324c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 733ac35ff17SAlexander V. Chernikov } 734ac35ff17SAlexander V. Chernikov 73581d3153dSAlexander V. Chernikov static int 73681d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 73781d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 73881d3153dSAlexander V. Chernikov { 73981d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 74081d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 74181d3153dSAlexander V. Chernikov uint8_t type, vtype; 74281d3153dSAlexander V. Chernikov int error; 74381d3153dSAlexander V. Chernikov size_t sz; 74481d3153dSAlexander V. Chernikov 74581d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 74681d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 74781d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 74881d3153dSAlexander V. Chernikov 74981d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 75081d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 75181d3153dSAlexander V. Chernikov tent->idx = 1; 75281d3153dSAlexander V. Chernikov 75381d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 75481d3153dSAlexander V. Chernikov oh->ntlv.type = type; 75581d3153dSAlexander V. Chernikov 75681d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 75781d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 75881d3153dSAlexander V. Chernikov return (error); 75981d3153dSAlexander V. Chernikov 76081d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 76181d3153dSAlexander V. Chernikov return (EINVAL); 76281d3153dSAlexander V. Chernikov 76381d3153dSAlexander V. Chernikov *xtent = *tent; 76481d3153dSAlexander V. Chernikov 76581d3153dSAlexander V. Chernikov return (0); 76681d3153dSAlexander V. Chernikov } 76781d3153dSAlexander V. Chernikov 76881d3153dSAlexander V. Chernikov static void 76981d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 77081d3153dSAlexander V. Chernikov { 77181d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 77281d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 773914bffb6SAlexander V. Chernikov char key[64]; 77481d3153dSAlexander V. Chernikov int error; 77581d3153dSAlexander V. Chernikov 77681d3153dSAlexander V. Chernikov if (ac == 0) 77781d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 77881d3153dSAlexander V. Chernikov 779914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 780914bffb6SAlexander V. Chernikov 781914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 78281d3153dSAlexander V. Chernikov 78381d3153dSAlexander V. Chernikov switch (error) { 78481d3153dSAlexander V. Chernikov case 0: 78581d3153dSAlexander V. Chernikov break; 78681d3153dSAlexander V. Chernikov case ESRCH: 78781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 78881d3153dSAlexander V. Chernikov case ENOENT: 78981d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 79081d3153dSAlexander V. Chernikov case ENOTSUP: 79181d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 79281d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 79381d3153dSAlexander V. Chernikov default: 79481d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 79581d3153dSAlexander V. Chernikov } 79681d3153dSAlexander V. Chernikov 79781d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 79881d3153dSAlexander V. Chernikov } 799ac35ff17SAlexander V. Chernikov 800ac35ff17SAlexander V. Chernikov static void 801914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 802914bffb6SAlexander V. Chernikov uint8_t tflags) 803ac35ff17SAlexander V. Chernikov { 804914bffb6SAlexander V. Chernikov char *p, *pp; 805ac35ff17SAlexander V. Chernikov int mask, af; 806914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 807914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 808ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 809914bffb6SAlexander V. Chernikov uint16_t port; 810914bffb6SAlexander V. Chernikov struct protoent *pent; 811914bffb6SAlexander V. Chernikov struct servent *sent; 812ac35ff17SAlexander V. Chernikov int masklen; 813ac35ff17SAlexander V. Chernikov 814ac35ff17SAlexander V. Chernikov masklen = 0; 815ac35ff17SAlexander V. Chernikov af = 0; 816ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 817ac35ff17SAlexander V. Chernikov 818ac35ff17SAlexander V. Chernikov switch (type) { 819ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 820ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 821ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 822ac35ff17SAlexander V. Chernikov *p = '\0'; 823ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 824ac35ff17SAlexander V. Chernikov } 825ac35ff17SAlexander V. Chernikov 826ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 827ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 828ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 829ac35ff17SAlexander V. Chernikov p + 1); 830ac35ff17SAlexander V. Chernikov 831ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 832ac35ff17SAlexander V. Chernikov af = AF_INET; 833ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 834ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 835ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 836ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 837ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 838ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 839ac35ff17SAlexander V. Chernikov p + 1); 840ac35ff17SAlexander V. Chernikov 841ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 842ac35ff17SAlexander V. Chernikov af = AF_INET6; 843ac35ff17SAlexander V. Chernikov } else { 844ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 845ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 846ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 847ac35ff17SAlexander V. Chernikov 848ac35ff17SAlexander V. Chernikov masklen = 32; 849ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 850ac35ff17SAlexander V. Chernikov af = AF_INET; 851ac35ff17SAlexander V. Chernikov } 852ac35ff17SAlexander V. Chernikov break; 853ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 854ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 855ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 856ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 857ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 858ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 859ac35ff17SAlexander V. Chernikov break; 860b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 861ac35ff17SAlexander V. Chernikov /* Port or any other key */ 862ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 863ac35ff17SAlexander V. Chernikov if (*p != '\0') 864ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 865ac35ff17SAlexander V. Chernikov 866ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 867ac35ff17SAlexander V. Chernikov *pkey = key; 868ac35ff17SAlexander V. Chernikov masklen = 32; 869ac35ff17SAlexander V. Chernikov break; 870914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 871914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 872914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 873914bffb6SAlexander V. Chernikov af = 0; 874914bffb6SAlexander V. Chernikov 875914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 876914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 877914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 878914bffb6SAlexander V. Chernikov *p++ = '\0'; 879914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 880914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 881914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 882914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 883914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 884914bffb6SAlexander V. Chernikov af = AF_INET; 885914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 886914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 887914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 888914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 889914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 890914bffb6SAlexander V. Chernikov af = AF_INET6; 891914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 892914bffb6SAlexander V. Chernikov } 893914bffb6SAlexander V. Chernikov 894914bffb6SAlexander V. Chernikov arg = p; 895914bffb6SAlexander V. Chernikov } 896914bffb6SAlexander V. Chernikov 897914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 898914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 899914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 900914bffb6SAlexander V. Chernikov *p++ = '\0'; 901914bffb6SAlexander V. Chernikov 902914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 903914bffb6SAlexander V. Chernikov if (*pp != '\0') { 904914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 905914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 906914bffb6SAlexander V. Chernikov arg); 907914bffb6SAlexander V. Chernikov else 908914bffb6SAlexander V. Chernikov key = pent->p_proto; 909914bffb6SAlexander V. Chernikov } 910914bffb6SAlexander V. Chernikov 911914bffb6SAlexander V. Chernikov if (key > 255) 912914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 913914bffb6SAlexander V. Chernikov 914914bffb6SAlexander V. Chernikov tfe->proto = key; 915914bffb6SAlexander V. Chernikov 916914bffb6SAlexander V. Chernikov arg = p; 917914bffb6SAlexander V. Chernikov } 918914bffb6SAlexander V. Chernikov 919914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 920914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 921914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 922914bffb6SAlexander V. Chernikov *p++ = '\0'; 923914bffb6SAlexander V. Chernikov 924914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 925914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 926914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 927914bffb6SAlexander V. Chernikov arg); 928914bffb6SAlexander V. Chernikov else 929914bffb6SAlexander V. Chernikov key = sent->s_port; 930914bffb6SAlexander V. Chernikov } 931914bffb6SAlexander V. Chernikov 932914bffb6SAlexander V. Chernikov tfe->sport = port; 933914bffb6SAlexander V. Chernikov 934914bffb6SAlexander V. Chernikov arg = p; 935914bffb6SAlexander V. Chernikov } 936914bffb6SAlexander V. Chernikov 937914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 938914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 939914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 940914bffb6SAlexander V. Chernikov *p++ = '\0'; 941914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 942914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 943914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 944914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 945914bffb6SAlexander V. Chernikov "Inconsistent address family"); 946914bffb6SAlexander V. Chernikov af = AF_INET; 947914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 948914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 949914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 950914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 951914bffb6SAlexander V. Chernikov "Inconsistent address family"); 952914bffb6SAlexander V. Chernikov af = AF_INET6; 953914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 954914bffb6SAlexander V. Chernikov } 955914bffb6SAlexander V. Chernikov 956914bffb6SAlexander V. Chernikov arg = p; 957914bffb6SAlexander V. Chernikov } 958914bffb6SAlexander V. Chernikov 959914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 960914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 961914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 962914bffb6SAlexander V. Chernikov *p++ = '\0'; 963914bffb6SAlexander V. Chernikov 964914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 965914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 966914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 967914bffb6SAlexander V. Chernikov arg); 968914bffb6SAlexander V. Chernikov else 969914bffb6SAlexander V. Chernikov key = sent->s_port; 970914bffb6SAlexander V. Chernikov } 971914bffb6SAlexander V. Chernikov 972914bffb6SAlexander V. Chernikov tfe->dport = port; 973914bffb6SAlexander V. Chernikov 974914bffb6SAlexander V. Chernikov arg = p; 975914bffb6SAlexander V. Chernikov } 976914bffb6SAlexander V. Chernikov 977914bffb6SAlexander V. Chernikov tfe->af = af; 978914bffb6SAlexander V. Chernikov 979914bffb6SAlexander V. Chernikov break; 980914bffb6SAlexander V. Chernikov 981ac35ff17SAlexander V. Chernikov default: 982ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 983ac35ff17SAlexander V. Chernikov } 984ac35ff17SAlexander V. Chernikov 985ac35ff17SAlexander V. Chernikov tentry->subtype = af; 986ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 987ac35ff17SAlexander V. Chernikov } 988ac35ff17SAlexander V. Chernikov 989ac35ff17SAlexander V. Chernikov static void 990ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 99181d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 992ac35ff17SAlexander V. Chernikov { 993914bffb6SAlexander V. Chernikov uint8_t type, tflags, vtype; 994ac35ff17SAlexander V. Chernikov int error; 995db785d31SAlexander V. Chernikov char *del; 996ac35ff17SAlexander V. Chernikov 997ac35ff17SAlexander V. Chernikov type = 0; 998914bffb6SAlexander V. Chernikov tflags = 0; 999ac35ff17SAlexander V. Chernikov vtype = 0; 1000ac35ff17SAlexander V. Chernikov 100181d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 100281d3153dSAlexander V. Chernikov 100381d3153dSAlexander V. Chernikov if (error == 0) { 100481d3153dSAlexander V. Chernikov /* Table found. */ 100581d3153dSAlexander V. Chernikov type = xi->type; 1006914bffb6SAlexander V. Chernikov tflags = xi->tflags; 100781d3153dSAlexander V. Chernikov vtype = xi->vtype; 100881d3153dSAlexander V. Chernikov } else { 100981d3153dSAlexander V. Chernikov if (error != ESRCH) 101081d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 101181d3153dSAlexander V. Chernikov oh->ntlv.name); 1012ac35ff17SAlexander V. Chernikov /* 101381d3153dSAlexander V. Chernikov * Table does not exist. 101481d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 101581d3153dSAlexander V. Chernikov * before failing. 1016ac35ff17SAlexander V. Chernikov */ 1017db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 1018db785d31SAlexander V. Chernikov *del = '\0'; 1019ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 1020ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 1021ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 1022ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 1023ac35ff17SAlexander V. Chernikov /* 102481d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 102581d3153dSAlexander V. Chernikov * This should be changed for MFC. 1026ac35ff17SAlexander V. Chernikov */ 102781d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 102881d3153dSAlexander V. Chernikov } else { 102981d3153dSAlexander V. Chernikov /* Inknown key */ 103081d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1031db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 103281d3153dSAlexander V. Chernikov } 1033db785d31SAlexander V. Chernikov if (del != NULL) 1034db785d31SAlexander V. Chernikov *del = '/'; 1035ac35ff17SAlexander V. Chernikov } 1036ac35ff17SAlexander V. Chernikov 1037914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1038ac35ff17SAlexander V. Chernikov 1039ac35ff17SAlexander V. Chernikov *ptype = type; 1040ac35ff17SAlexander V. Chernikov *pvtype = vtype; 1041ac35ff17SAlexander V. Chernikov } 1042ac35ff17SAlexander V. Chernikov 1043ac35ff17SAlexander V. Chernikov static void 1044ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1045ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 1046ac35ff17SAlexander V. Chernikov { 1047ac35ff17SAlexander V. Chernikov int code; 1048ac35ff17SAlexander V. Chernikov char *p; 1049ac35ff17SAlexander V. Chernikov 1050ac35ff17SAlexander V. Chernikov switch (vtype) { 1051ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 1052ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1053ac35ff17SAlexander V. Chernikov if (*p != '\0') 1054ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 1055ac35ff17SAlexander V. Chernikov break; 1056ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 1057ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 1058ac35ff17SAlexander V. Chernikov break; 1059ac35ff17SAlexander V. Chernikov /* Try hostname */ 1060ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 1061ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 1062ac35ff17SAlexander V. Chernikov break; 1063ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1064ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 1065ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 1066ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 1067ac35ff17SAlexander V. Chernikov } else { 1068ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 1069ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 1070ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 1071ac35ff17SAlexander V. Chernikov } 1072ac35ff17SAlexander V. Chernikov tent->value = code; 1073ac35ff17SAlexander V. Chernikov break; 1074ac35ff17SAlexander V. Chernikov default: 1075ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 1076ac35ff17SAlexander V. Chernikov } 1077ac35ff17SAlexander V. Chernikov } 1078f1220db8SAlexander V. Chernikov 1079f1220db8SAlexander V. Chernikov /* 1080f1220db8SAlexander V. Chernikov * Compare table names. 1081f1220db8SAlexander V. Chernikov * Honor number comparison. 1082f1220db8SAlexander V. Chernikov */ 1083f1220db8SAlexander V. Chernikov static int 1084f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1085f1220db8SAlexander V. Chernikov { 1086f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1087f1220db8SAlexander V. Chernikov 1088f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1089f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1090f1220db8SAlexander V. Chernikov 109168394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1092f1220db8SAlexander V. Chernikov } 1093f1220db8SAlexander V. Chernikov 1094f1220db8SAlexander V. Chernikov /* 1095f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1096f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1097f1220db8SAlexander V. Chernikov * Returns 0 on success. 1098f1220db8SAlexander V. Chernikov */ 1099f1220db8SAlexander V. Chernikov static int 1100f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1101f1220db8SAlexander V. Chernikov { 1102f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 1103f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1104f1220db8SAlexander V. Chernikov size_t sz; 1105f1220db8SAlexander V. Chernikov int i, error; 1106f1220db8SAlexander V. Chernikov 1107f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 1108f1220db8SAlexander V. Chernikov sz = sizeof(req); 1109f1220db8SAlexander V. Chernikov 1110d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 1111f1220db8SAlexander V. Chernikov return (errno); 1112f1220db8SAlexander V. Chernikov 1113f1220db8SAlexander V. Chernikov sz = req.size; 1114f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1115f1220db8SAlexander V. Chernikov return (ENOMEM); 1116f1220db8SAlexander V. Chernikov 1117f1220db8SAlexander V. Chernikov olh->size = sz; 1118d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 1119f1220db8SAlexander V. Chernikov free(olh); 1120f1220db8SAlexander V. Chernikov return (errno); 1121f1220db8SAlexander V. Chernikov } 1122f1220db8SAlexander V. Chernikov 1123f1220db8SAlexander V. Chernikov if (sort != 0) 1124f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1125f1220db8SAlexander V. Chernikov 1126f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1127f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1128f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1129f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1130f1220db8SAlexander V. Chernikov } 1131f1220db8SAlexander V. Chernikov 1132f1220db8SAlexander V. Chernikov free(olh); 1133f1220db8SAlexander V. Chernikov 1134f1220db8SAlexander V. Chernikov return (0); 1135f1220db8SAlexander V. Chernikov } 1136f1220db8SAlexander V. Chernikov 1137f1220db8SAlexander V. Chernikov /* 1138f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1139d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 1140d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 1141f1220db8SAlexander V. Chernikov * 1142f1220db8SAlexander V. Chernikov * Returns 0 on success. 1143f1220db8SAlexander V. Chernikov */ 1144f1220db8SAlexander V. Chernikov static int 1145f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 1146f1220db8SAlexander V. Chernikov { 1147f1220db8SAlexander V. Chernikov size_t sz; 114881d3153dSAlexander V. Chernikov int error, c; 1149f1220db8SAlexander V. Chernikov 115081d3153dSAlexander V. Chernikov sz = 0; 115181d3153dSAlexander V. Chernikov for (c = 0; c < 3; c++) { 1152f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 115381d3153dSAlexander V. Chernikov if (sz < i->size) 1154f1220db8SAlexander V. Chernikov sz = i->size; 1155f1220db8SAlexander V. Chernikov 1156d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 115781d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1158d3a4f924SAlexander V. Chernikov 115981d3153dSAlexander V. Chernikov if (error != ENOMEM) 1160f1220db8SAlexander V. Chernikov return (errno); 116181d3153dSAlexander V. Chernikov } 1162f1220db8SAlexander V. Chernikov 116381d3153dSAlexander V. Chernikov return (ENOMEM); 1164f1220db8SAlexander V. Chernikov } 1165f1220db8SAlexander V. Chernikov 1166f1220db8SAlexander V. Chernikov /* 1167f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1168f1220db8SAlexander V. Chernikov */ 1169f1220db8SAlexander V. Chernikov static void 1170f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1171f1220db8SAlexander V. Chernikov { 117281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 117381d3153dSAlexander V. Chernikov uint32_t count; 1174f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1175f1220db8SAlexander V. Chernikov 1176f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 117781d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1178f1220db8SAlexander V. Chernikov 1179f1220db8SAlexander V. Chernikov if (need_header) 1180f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1181f1220db8SAlexander V. Chernikov 1182f1220db8SAlexander V. Chernikov count = i->count; 1183f1220db8SAlexander V. Chernikov while (count > 0) { 118481d3153dSAlexander V. Chernikov table_show_entry(i, tent); 118581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 118681d3153dSAlexander V. Chernikov count--; 118781d3153dSAlexander V. Chernikov } 118881d3153dSAlexander V. Chernikov } 118981d3153dSAlexander V. Chernikov 119081d3153dSAlexander V. Chernikov static void 119181d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 119281d3153dSAlexander V. Chernikov { 1193914bffb6SAlexander V. Chernikov char *comma, tbuf[128], pval[32]; 1194914bffb6SAlexander V. Chernikov void *paddr; 119581d3153dSAlexander V. Chernikov uint32_t tval; 1196914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 119781d3153dSAlexander V. Chernikov 119881d3153dSAlexander V. Chernikov tval = tent->value; 119981d3153dSAlexander V. Chernikov 1200914bffb6SAlexander V. Chernikov if (co.do_value_as_ip) { 1201914bffb6SAlexander V. Chernikov tval = htonl(tval); 1202914bffb6SAlexander V. Chernikov inet_ntop(AF_INET, &tval, pval, sizeof(pval)); 1203914bffb6SAlexander V. Chernikov } else 1204914bffb6SAlexander V. Chernikov snprintf(pval, sizeof(pval), "%u", tval); 1205914bffb6SAlexander V. Chernikov 1206f1220db8SAlexander V. Chernikov switch (i->type) { 1207f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1208f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 120981d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1210914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1211f1220db8SAlexander V. Chernikov break; 1212f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1213f1220db8SAlexander V. Chernikov /* Interface names */ 1214914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1215b23d5de9SAlexander V. Chernikov break; 1216b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1217b23d5de9SAlexander V. Chernikov /* numbers */ 1218914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1219b23d5de9SAlexander V. Chernikov break; 1220914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1221914bffb6SAlexander V. Chernikov /* flows */ 1222914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1223914bffb6SAlexander V. Chernikov comma = ""; 1224914bffb6SAlexander V. Chernikov 1225914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1226914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1227914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1228914bffb6SAlexander V. Chernikov else 1229914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1230914bffb6SAlexander V. Chernikov 1231914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1232914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1233914bffb6SAlexander V. Chernikov comma = ","; 1234914bffb6SAlexander V. Chernikov } 1235914bffb6SAlexander V. Chernikov 1236914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1237914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1238914bffb6SAlexander V. Chernikov comma = ","; 1239914bffb6SAlexander V. Chernikov } 1240914bffb6SAlexander V. Chernikov 1241914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1242914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1243914bffb6SAlexander V. Chernikov comma = ","; 1244914bffb6SAlexander V. Chernikov } 1245914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1246914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1247914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1248914bffb6SAlexander V. Chernikov else 1249914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1250914bffb6SAlexander V. Chernikov 1251914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1252914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1253914bffb6SAlexander V. Chernikov comma = ","; 1254914bffb6SAlexander V. Chernikov } 1255914bffb6SAlexander V. Chernikov 1256914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1257914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1258914bffb6SAlexander V. Chernikov comma = ","; 1259914bffb6SAlexander V. Chernikov } 1260914bffb6SAlexander V. Chernikov 1261914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1262f1220db8SAlexander V. Chernikov } 1263f1220db8SAlexander V. Chernikov } 1264f1220db8SAlexander V. Chernikov 12659d099b4fSAlexander V. Chernikov static int 12669d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 12679d099b4fSAlexander V. Chernikov { 12689d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 12699d099b4fSAlexander V. Chernikov size_t sz; 12709d099b4fSAlexander V. Chernikov int error; 12719d099b4fSAlexander V. Chernikov 12729d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 12739d099b4fSAlexander V. Chernikov sz = sizeof(req); 12749d099b4fSAlexander V. Chernikov 12759d099b4fSAlexander V. Chernikov error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); 12769d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 12779d099b4fSAlexander V. Chernikov return (error); 12789d099b4fSAlexander V. Chernikov 12799d099b4fSAlexander V. Chernikov sz = req.size; 12809d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 12819d099b4fSAlexander V. Chernikov return (ENOMEM); 12829d099b4fSAlexander V. Chernikov 12839d099b4fSAlexander V. Chernikov olh->size = sz; 12849d099b4fSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { 12859d099b4fSAlexander V. Chernikov free(olh); 12869d099b4fSAlexander V. Chernikov return (error); 12879d099b4fSAlexander V. Chernikov } 12889d099b4fSAlexander V. Chernikov 12899d099b4fSAlexander V. Chernikov *polh = olh; 12909d099b4fSAlexander V. Chernikov return (0); 12919d099b4fSAlexander V. Chernikov } 12929d099b4fSAlexander V. Chernikov 12939d099b4fSAlexander V. Chernikov void 12949d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 12959d099b4fSAlexander V. Chernikov { 12969d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 12979d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 12989d099b4fSAlexander V. Chernikov int error, i; 12999d099b4fSAlexander V. Chernikov const char *atype; 13009d099b4fSAlexander V. Chernikov 13019d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 13029d099b4fSAlexander V. Chernikov if (error != 0) 13039d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 13049d099b4fSAlexander V. Chernikov 13059d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 13069d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 13079d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 13089d099b4fSAlexander V. Chernikov atype = "unknown"; 13098ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 13108ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 13119d099b4fSAlexander V. Chernikov 13129d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 13139d099b4fSAlexander V. Chernikov } 13149d099b4fSAlexander V. Chernikov 13159d099b4fSAlexander V. Chernikov free(olh); 13169d099b4fSAlexander V. Chernikov } 13179d099b4fSAlexander V. Chernikov 13186c2997ffSAlexander V. Chernikov int 13196c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 13206c2997ffSAlexander V. Chernikov { 13216c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 13226c2997ffSAlexander V. Chernikov 13236c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 13246c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 13256c2997ffSAlexander V. Chernikov 13266c2997ffSAlexander V. Chernikov if (a->set < b->set) 13276c2997ffSAlexander V. Chernikov return (-1); 13286c2997ffSAlexander V. Chernikov else if (a->set > b->set) 13296c2997ffSAlexander V. Chernikov return (1); 13306c2997ffSAlexander V. Chernikov 13316c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 13326c2997ffSAlexander V. Chernikov return (-1); 13336c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 13346c2997ffSAlexander V. Chernikov return (1); 13356c2997ffSAlexander V. Chernikov 13366c2997ffSAlexander V. Chernikov return (0); 13376c2997ffSAlexander V. Chernikov } 1338563b5ab1SAlexander V. Chernikov 1339563b5ab1SAlexander V. Chernikov int 13406c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1341563b5ab1SAlexander V. Chernikov { 1342563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1343563b5ab1SAlexander V. Chernikov uint16_t key; 1344563b5ab1SAlexander V. Chernikov 1345563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1346563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1347563b5ab1SAlexander V. Chernikov 1348563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1349563b5ab1SAlexander V. Chernikov return (-1); 1350563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1351563b5ab1SAlexander V. Chernikov return (1); 1352563b5ab1SAlexander V. Chernikov 1353563b5ab1SAlexander V. Chernikov return (0); 1354563b5ab1SAlexander V. Chernikov } 1355563b5ab1SAlexander V. Chernikov 1356563b5ab1SAlexander V. Chernikov /* 1357563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1358563b5ab1SAlexander V. Chernikov * Uses the following facts: 1359563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1360563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1361563b5ab1SAlexander V. Chernikov * 1362563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1363563b5ab1SAlexander V. Chernikov */ 1364563b5ab1SAlexander V. Chernikov char * 1365563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1366563b5ab1SAlexander V. Chernikov { 1367563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1368563b5ab1SAlexander V. Chernikov 1369563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 13706c2997ffSAlexander V. Chernikov compare_kntlv); 1371563b5ab1SAlexander V. Chernikov 1372563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1373563b5ab1SAlexander V. Chernikov return (ntlv->name); 1374563b5ab1SAlexander V. Chernikov 1375563b5ab1SAlexander V. Chernikov return (NULL); 1376563b5ab1SAlexander V. Chernikov } 1377563b5ab1SAlexander V. Chernikov 13786c2997ffSAlexander V. Chernikov void 13796c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 13806c2997ffSAlexander V. Chernikov { 13816c2997ffSAlexander V. Chernikov 13826c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 13836c2997ffSAlexander V. Chernikov } 13846c2997ffSAlexander V. Chernikov 13856c2997ffSAlexander V. Chernikov int 13866c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 13876c2997ffSAlexander V. Chernikov { 13886c2997ffSAlexander V. Chernikov int c, i, l; 13896c2997ffSAlexander V. Chernikov 13906c2997ffSAlexander V. Chernikov /* 13916c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 13926c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 1393ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 13946c2997ffSAlexander V. Chernikov */ 13956c2997ffSAlexander V. Chernikov l = strlen(tablename); 13966c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 13976c2997ffSAlexander V. Chernikov return (EINVAL); 13986c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 13996c2997ffSAlexander V. Chernikov c = tablename[i]; 14006c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 14016c2997ffSAlexander V. Chernikov c == '-' || c == '.') 14026c2997ffSAlexander V. Chernikov continue; 14036c2997ffSAlexander V. Chernikov return (EINVAL); 14046c2997ffSAlexander V. Chernikov } 14056c2997ffSAlexander V. Chernikov 1406ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1407ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1408ac35ff17SAlexander V. Chernikov return (EINVAL); 1409ac35ff17SAlexander V. Chernikov 14106c2997ffSAlexander V. Chernikov return (0); 14116c2997ffSAlexander V. Chernikov } 14126c2997ffSAlexander V. Chernikov 1413