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[]); 59*46d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second); 60*46d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second); 61ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 62f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 63ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, 64ac35ff17SAlexander V. Chernikov uint16_t uidx); 65f1220db8SAlexander V. Chernikov 66f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 67f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 68f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh); 69f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 7081d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 71f1220db8SAlexander V. Chernikov 72ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 7381d3153dSAlexander V. Chernikov char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); 74ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 75ac35ff17SAlexander V. Chernikov char *arg, uint8_t type, uint8_t vtype); 76ac35ff17SAlexander V. Chernikov 77f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 78f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 79f1220db8SAlexander V. Chernikov 80f1220db8SAlexander V. Chernikov #ifndef s6_addr32 81f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 82f1220db8SAlexander V. Chernikov #endif 83f1220db8SAlexander V. Chernikov 84ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 85ac35ff17SAlexander V. Chernikov { "cidr", IPFW_TABLE_CIDR }, 86ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 87b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 88914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 89ac35ff17SAlexander V. Chernikov { NULL, 0 } 90ac35ff17SAlexander V. Chernikov }; 91ac35ff17SAlexander V. Chernikov 92ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 93ac35ff17SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 94ac35ff17SAlexander V. Chernikov { "ip", IPFW_VTYPE_IP }, 95ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 96ac35ff17SAlexander V. Chernikov { NULL, 0 } 97ac35ff17SAlexander V. Chernikov }; 98ac35ff17SAlexander V. Chernikov 99ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 100ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 101ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 102*46d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 103ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 104ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 105*46d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 106ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 107358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 108ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 10981d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 110ac35ff17SAlexander V. Chernikov { NULL, 0 } 111ac35ff17SAlexander V. Chernikov }; 112ac35ff17SAlexander V. Chernikov 113f1220db8SAlexander V. Chernikov static int 114f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 115f1220db8SAlexander V. Chernikov { 116f1220db8SAlexander V. Chernikov struct hostent *he; 117f1220db8SAlexander V. Chernikov 118f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 119f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 120f1220db8SAlexander V. Chernikov return(-1); 121f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 122f1220db8SAlexander V. Chernikov } 123f1220db8SAlexander V. Chernikov return(0); 124f1220db8SAlexander V. Chernikov } 125f1220db8SAlexander V. Chernikov 126f1220db8SAlexander V. Chernikov /* 127f1220db8SAlexander V. Chernikov * This one handles all table-related commands 128ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 129ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 130ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 131ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 132ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 133ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 134ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 135f1220db8SAlexander V. Chernikov */ 136f1220db8SAlexander V. Chernikov void 137f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 138f1220db8SAlexander V. Chernikov { 139ac35ff17SAlexander V. Chernikov int do_add, is_all; 140ac35ff17SAlexander V. Chernikov int error, tcmd; 141ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 142ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 143f1220db8SAlexander V. Chernikov char *tablename; 144ac35ff17SAlexander V. Chernikov uint32_t set; 145358b9d09SAlexander V. Chernikov void *arg; 146f1220db8SAlexander V. Chernikov 147ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 148ac35ff17SAlexander V. Chernikov is_all = 0; 149ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 150ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 151ac35ff17SAlexander V. Chernikov else 152ac35ff17SAlexander V. Chernikov set = 0; 153f1220db8SAlexander V. Chernikov 154f1220db8SAlexander V. Chernikov ac--; av++; 1559d099b4fSAlexander V. Chernikov NEED1("table needs name"); 156f1220db8SAlexander V. Chernikov tablename = *av; 157f1220db8SAlexander V. Chernikov 158ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 159ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 160ac35ff17SAlexander V. Chernikov oh.idx = 1; 161ac35ff17SAlexander V. Chernikov } else { 162ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 163ac35ff17SAlexander V. Chernikov is_all = 1; 164ac35ff17SAlexander V. Chernikov else 165ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 166ac35ff17SAlexander V. Chernikov } 167ac35ff17SAlexander V. Chernikov ac--; av++; 1689d099b4fSAlexander V. Chernikov NEED1("table needs command"); 169ac35ff17SAlexander V. Chernikov 170ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 171ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 172ac35ff17SAlexander V. Chernikov 173ac35ff17SAlexander V. Chernikov switch (tcmd) { 174ac35ff17SAlexander V. Chernikov case TOK_LIST: 175ac35ff17SAlexander V. Chernikov case TOK_INFO: 176358b9d09SAlexander V. Chernikov case TOK_DETAIL: 177ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 178ac35ff17SAlexander V. Chernikov break; 179ac35ff17SAlexander V. Chernikov default: 180ac35ff17SAlexander V. Chernikov if (is_all != 0) 181ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 182ac35ff17SAlexander V. Chernikov } 183ac35ff17SAlexander V. Chernikov 184ac35ff17SAlexander V. Chernikov switch (tcmd) { 185ac35ff17SAlexander V. Chernikov case TOK_ADD: 186ac35ff17SAlexander V. Chernikov case TOK_DEL: 187f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 188f1220db8SAlexander V. Chernikov ac--; av++; 189ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 190ac35ff17SAlexander V. Chernikov break; 191ac35ff17SAlexander V. Chernikov case TOK_CREATE: 192f1220db8SAlexander V. Chernikov ac--; av++; 193ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 194ac35ff17SAlexander V. Chernikov break; 195ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 196ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 197ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 198ac35ff17SAlexander V. Chernikov break; 199ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 200f1220db8SAlexander V. Chernikov if (is_all == 0) { 201ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 202f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 203f1220db8SAlexander V. Chernikov tablename); 204f1220db8SAlexander V. Chernikov } else { 205ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 206f1220db8SAlexander V. Chernikov if (error != 0) 207f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 208f1220db8SAlexander V. Chernikov } 209ac35ff17SAlexander V. Chernikov break; 210*46d52008SAlexander V. Chernikov case TOK_SWAP: 211*46d52008SAlexander V. Chernikov ac--; av++; 212*46d52008SAlexander V. Chernikov NEED1("second table name required"); 213*46d52008SAlexander V. Chernikov table_swap(&oh, *av); 214*46d52008SAlexander V. Chernikov break; 215358b9d09SAlexander V. Chernikov case TOK_DETAIL: 216ac35ff17SAlexander V. Chernikov case TOK_INFO: 217358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 218f1220db8SAlexander V. Chernikov if (is_all == 0) { 219ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 220f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 221358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 222f1220db8SAlexander V. Chernikov } else { 223358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 224f1220db8SAlexander V. Chernikov if (error != 0) 225f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 226f1220db8SAlexander V. Chernikov } 227ac35ff17SAlexander V. Chernikov break; 228ac35ff17SAlexander V. Chernikov case TOK_LIST: 229ac35ff17SAlexander V. Chernikov if (is_all == 0) { 230ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 231ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 232ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 233ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 234f1220db8SAlexander V. Chernikov } else { 235ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 236ac35ff17SAlexander V. Chernikov if (error != 0) 237ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 238f1220db8SAlexander V. Chernikov } 239ac35ff17SAlexander V. Chernikov break; 24081d3153dSAlexander V. Chernikov case TOK_LOOKUP: 24181d3153dSAlexander V. Chernikov ac--; av++; 24281d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 24381d3153dSAlexander V. Chernikov break; 244f1220db8SAlexander V. Chernikov } 245f1220db8SAlexander V. Chernikov } 246f1220db8SAlexander V. Chernikov 247f1220db8SAlexander V. Chernikov static void 248ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 249f1220db8SAlexander V. Chernikov { 250f1220db8SAlexander V. Chernikov 251563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 252f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 253f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 254ac35ff17SAlexander V. Chernikov ntlv->set = set; 255f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 256f1220db8SAlexander V. Chernikov } 257f1220db8SAlexander V. Chernikov 258f1220db8SAlexander V. Chernikov static void 259f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 260f1220db8SAlexander V. Chernikov { 261f1220db8SAlexander V. Chernikov 262f1220db8SAlexander V. Chernikov oh->idx = 1; 26381d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 264ac35ff17SAlexander V. Chernikov } 265ac35ff17SAlexander V. Chernikov 266ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 267ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 268ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 269ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 2704c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 271ac35ff17SAlexander V. Chernikov { NULL, 0 } 272ac35ff17SAlexander V. Chernikov }; 273ac35ff17SAlexander V. Chernikov 274914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 275914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 276914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 277914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 278914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 279914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 280914bffb6SAlexander V. Chernikov { NULL, 0 } 281914bffb6SAlexander V. Chernikov }; 282914bffb6SAlexander V. Chernikov 283914bffb6SAlexander V. Chernikov int 284914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 285914bffb6SAlexander V. Chernikov { 286914bffb6SAlexander V. Chernikov uint8_t fset, fclear; 287914bffb6SAlexander V. Chernikov 288914bffb6SAlexander V. Chernikov /* Parse type options */ 289914bffb6SAlexander V. Chernikov switch(ttype) { 290914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 291914bffb6SAlexander V. Chernikov fset = fclear = 0; 292914bffb6SAlexander V. Chernikov fill_flags(flowtypecmds, p, &fset, 293914bffb6SAlexander V. Chernikov &fclear); 294914bffb6SAlexander V. Chernikov *tflags = fset; 295914bffb6SAlexander V. Chernikov break; 296914bffb6SAlexander V. Chernikov default: 297914bffb6SAlexander V. Chernikov return (EX_USAGE); 298914bffb6SAlexander V. Chernikov } 299914bffb6SAlexander V. Chernikov 300914bffb6SAlexander V. Chernikov return (0); 301914bffb6SAlexander V. Chernikov } 302914bffb6SAlexander V. Chernikov 303914bffb6SAlexander V. Chernikov void 304914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 305914bffb6SAlexander V. Chernikov { 306914bffb6SAlexander V. Chernikov const char *tname; 307914bffb6SAlexander V. Chernikov int l; 308914bffb6SAlexander V. Chernikov 309914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 310914bffb6SAlexander V. Chernikov tname = "unknown"; 311914bffb6SAlexander V. Chernikov 312914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 313914bffb6SAlexander V. Chernikov tbuf += l; 314914bffb6SAlexander V. Chernikov size -= l; 315914bffb6SAlexander V. Chernikov 316914bffb6SAlexander V. Chernikov switch(type) { 317914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 318914bffb6SAlexander V. Chernikov if (tflags != 0) { 319914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 320914bffb6SAlexander V. Chernikov l--; 321914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 322914bffb6SAlexander V. Chernikov } 323914bffb6SAlexander V. Chernikov break; 324914bffb6SAlexander V. Chernikov } 325914bffb6SAlexander V. Chernikov } 326914bffb6SAlexander V. Chernikov 327ac35ff17SAlexander V. Chernikov /* 328ac35ff17SAlexander V. Chernikov * Creates new table 329ac35ff17SAlexander V. Chernikov * 330ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 331ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 332ac35ff17SAlexander V. Chernikov * [ algo algoname ] 333ac35ff17SAlexander V. Chernikov * 334ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 335ac35ff17SAlexander V. Chernikov */ 336ac35ff17SAlexander V. Chernikov static void 337ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 338ac35ff17SAlexander V. Chernikov { 339ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 340ac35ff17SAlexander V. Chernikov int error, tcmd, val; 341ac35ff17SAlexander V. Chernikov size_t sz; 342914bffb6SAlexander V. Chernikov char *p; 343ac35ff17SAlexander V. Chernikov char tbuf[128]; 344ac35ff17SAlexander V. Chernikov 345ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 346ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 347ac35ff17SAlexander V. Chernikov 348ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 349ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 350ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 351ac35ff17SAlexander V. Chernikov 352ac35ff17SAlexander V. Chernikov while (ac > 0) { 353ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 354ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 355ac35ff17SAlexander V. Chernikov ac--; av++; 356ac35ff17SAlexander V. Chernikov 357ac35ff17SAlexander V. Chernikov switch (tcmd) { 3584c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 3594c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 3604c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 3614c0c07a5SAlexander V. Chernikov ac--; av++; 3624c0c07a5SAlexander V. Chernikov break; 363ac35ff17SAlexander V. Chernikov case TOK_TYPE: 364ac35ff17SAlexander V. Chernikov NEED1("table type required"); 365914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 366914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 367914bffb6SAlexander V. Chernikov *p++ = '\0'; 368ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 369914bffb6SAlexander V. Chernikov if (val == -1) { 370914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 371914bffb6SAlexander V. Chernikov ", "); 372914bffb6SAlexander V. Chernikov errx(EX_USAGE, 373914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 374ac35ff17SAlexander V. Chernikov *av, tbuf); 375914bffb6SAlexander V. Chernikov } 376914bffb6SAlexander V. Chernikov xi.type = val; 377914bffb6SAlexander V. Chernikov if (p != NULL) { 378914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 379914bffb6SAlexander V. Chernikov if (error != 0) 380914bffb6SAlexander V. Chernikov errx(EX_USAGE, 381914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 382914bffb6SAlexander V. Chernikov } 383914bffb6SAlexander V. Chernikov ac--; av++; 384ac35ff17SAlexander V. Chernikov break; 385ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 386ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 387ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 388ac35ff17SAlexander V. Chernikov if (val != -1) { 389ac35ff17SAlexander V. Chernikov xi.vtype = val; 390ac35ff17SAlexander V. Chernikov ac--; av++; 391ac35ff17SAlexander V. Chernikov break; 392ac35ff17SAlexander V. Chernikov } 393ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 394ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 395ac35ff17SAlexander V. Chernikov *av, tbuf); 396ac35ff17SAlexander V. Chernikov break; 397ac35ff17SAlexander V. Chernikov case TOK_ALGO: 398ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 399ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 400ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 401ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 402ac35ff17SAlexander V. Chernikov ac--; av++; 403ac35ff17SAlexander V. Chernikov break; 404ac35ff17SAlexander V. Chernikov } 405ac35ff17SAlexander V. Chernikov } 406ac35ff17SAlexander V. Chernikov 407ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 408ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 409f1220db8SAlexander V. Chernikov } 410f1220db8SAlexander V. Chernikov 411f1220db8SAlexander V. Chernikov /* 412ac35ff17SAlexander V. Chernikov * Creates new table 413ac35ff17SAlexander V. Chernikov * 414ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 415ac35ff17SAlexander V. Chernikov * 416f1220db8SAlexander V. Chernikov * Returns 0 on success. 417f1220db8SAlexander V. Chernikov */ 418f1220db8SAlexander V. Chernikov static int 419ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 420f1220db8SAlexander V. Chernikov { 421ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 422ac35ff17SAlexander V. Chernikov int error; 423f1220db8SAlexander V. Chernikov 424ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 425ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 426ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 427ac35ff17SAlexander V. Chernikov 428ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 429ac35ff17SAlexander V. Chernikov 430ac35ff17SAlexander V. Chernikov return (error); 431ac35ff17SAlexander V. Chernikov } 432ac35ff17SAlexander V. Chernikov 433ac35ff17SAlexander V. Chernikov /* 434ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 435ac35ff17SAlexander V. Chernikov * Returns 0 on success. 436ac35ff17SAlexander V. Chernikov */ 437ac35ff17SAlexander V. Chernikov static int 438ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 439ac35ff17SAlexander V. Chernikov { 440ac35ff17SAlexander V. Chernikov 441ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 442f1220db8SAlexander V. Chernikov return (-1); 443f1220db8SAlexander V. Chernikov 444f1220db8SAlexander V. Chernikov return (0); 445f1220db8SAlexander V. Chernikov } 446f1220db8SAlexander V. Chernikov 447f1220db8SAlexander V. Chernikov /* 448ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 449f1220db8SAlexander V. Chernikov * Returns 0 on success. 450f1220db8SAlexander V. Chernikov */ 451f1220db8SAlexander V. Chernikov static int 452ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 453f1220db8SAlexander V. Chernikov { 454f1220db8SAlexander V. Chernikov 455ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 456f1220db8SAlexander V. Chernikov return (-1); 457f1220db8SAlexander V. Chernikov 458f1220db8SAlexander V. Chernikov return (0); 459f1220db8SAlexander V. Chernikov } 460f1220db8SAlexander V. Chernikov 461*46d52008SAlexander V. Chernikov static int 462*46d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 463*46d52008SAlexander V. Chernikov { 464*46d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 465*46d52008SAlexander V. Chernikov int error; 466*46d52008SAlexander V. Chernikov 467*46d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 468*46d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 469*46d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 470*46d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 471*46d52008SAlexander V. Chernikov 472*46d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 473*46d52008SAlexander V. Chernikov 474*46d52008SAlexander V. Chernikov return (error); 475*46d52008SAlexander V. Chernikov } 476*46d52008SAlexander V. Chernikov 477*46d52008SAlexander V. Chernikov /* 478*46d52008SAlexander V. Chernikov * Swaps given table with @second one. 479*46d52008SAlexander V. Chernikov */ 480*46d52008SAlexander V. Chernikov static int 481*46d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 482*46d52008SAlexander V. Chernikov { 483*46d52008SAlexander V. Chernikov int error; 484*46d52008SAlexander V. Chernikov 485*46d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 486*46d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 487*46d52008SAlexander V. Chernikov 488*46d52008SAlexander V. Chernikov error = table_do_swap(oh, second); 489*46d52008SAlexander V. Chernikov 490*46d52008SAlexander V. Chernikov switch (error) { 491*46d52008SAlexander V. Chernikov case EINVAL: 492*46d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 493*46d52008SAlexander V. Chernikov case EFBIG: 494*46d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 495*46d52008SAlexander V. Chernikov } 496*46d52008SAlexander V. Chernikov 497*46d52008SAlexander V. Chernikov return (0); 498*46d52008SAlexander V. Chernikov } 499*46d52008SAlexander V. Chernikov 500*46d52008SAlexander V. Chernikov 501f1220db8SAlexander V. Chernikov /* 502ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 503f1220db8SAlexander V. Chernikov * it inside @i. 504f1220db8SAlexander V. Chernikov * Returns 0 on success. 505f1220db8SAlexander V. Chernikov */ 506f1220db8SAlexander V. Chernikov static int 507ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 508f1220db8SAlexander V. Chernikov { 509f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 510ac35ff17SAlexander V. Chernikov int error; 511f1220db8SAlexander V. Chernikov size_t sz; 512f1220db8SAlexander V. Chernikov 513f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 514f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 515ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 516f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 517f1220db8SAlexander V. Chernikov 518ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 519ac35ff17SAlexander V. Chernikov return (error); 520f1220db8SAlexander V. Chernikov 521f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 522ac35ff17SAlexander V. Chernikov return (EINVAL); 523f1220db8SAlexander V. Chernikov 524f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 525f1220db8SAlexander V. Chernikov 526f1220db8SAlexander V. Chernikov return (0); 527f1220db8SAlexander V. Chernikov } 528f1220db8SAlexander V. Chernikov 5295f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 5305f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 5315f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 5325f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 5335f379342SAlexander V. Chernikov { NULL, 0 } 5345f379342SAlexander V. Chernikov }; 5355f379342SAlexander V. Chernikov 5365f379342SAlexander V. Chernikov struct ta_cldata { 5375f379342SAlexander V. Chernikov uint8_t taclass; 5385f379342SAlexander V. Chernikov uint8_t spare4; 5395f379342SAlexander V. Chernikov uint16_t itemsize; 5405f379342SAlexander V. Chernikov uint16_t itemsize6; 5415f379342SAlexander V. Chernikov uint32_t size; 5425f379342SAlexander V. Chernikov uint32_t count; 5435f379342SAlexander V. Chernikov }; 5445f379342SAlexander V. Chernikov 5455f379342SAlexander V. Chernikov /* 5465f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 5475f379342SAlexander V. Chernikov */ 5485f379342SAlexander V. Chernikov static void 5495f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 5505f379342SAlexander V. Chernikov const char *af, const char *taclass) 5515f379342SAlexander V. Chernikov { 5525f379342SAlexander V. Chernikov 5535f379342SAlexander V. Chernikov switch (d->taclass) { 5545f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 5555f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 5565f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 5575f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 5585f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 5595f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 5605f379342SAlexander V. Chernikov else 5615f379342SAlexander V. Chernikov printf(" size: %u items: %u " 5625f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 5635f379342SAlexander V. Chernikov d->size, d->count, 5645f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 5655f379342SAlexander V. Chernikov break; 5665f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 5675f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 5685f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 5695f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 5705f379342SAlexander V. Chernikov d->count, d->itemsize); 5715f379342SAlexander V. Chernikov else 5725f379342SAlexander V. Chernikov printf(" items: %u " 5735f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 5745f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 5755f379342SAlexander V. Chernikov break; 5765f379342SAlexander V. Chernikov default: 5775f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 5785f379342SAlexander V. Chernikov } 5795f379342SAlexander V. Chernikov } 5805f379342SAlexander V. Chernikov 581f1220db8SAlexander V. Chernikov /* 582f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 583f1220db8SAlexander V. Chernikov */ 584f1220db8SAlexander V. Chernikov static int 585f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 586f1220db8SAlexander V. Chernikov { 587914bffb6SAlexander V. Chernikov const char *vtype; 5885f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 5895f379342SAlexander V. Chernikov int afdata, afitem; 5905f379342SAlexander V. Chernikov struct ta_cldata d; 591914bffb6SAlexander V. Chernikov char ttype[64]; 592f1220db8SAlexander V. Chernikov 593914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 594ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 595ac35ff17SAlexander V. Chernikov vtype = "unknown"; 596ac35ff17SAlexander V. Chernikov 597914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 598914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 5999d099b4fSAlexander V. Chernikov printf(" valtype: %s, references: %u\n", vtype, i->refcnt); 6009d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 601f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 6024c0c07a5SAlexander V. Chernikov if (i->limit > 0) 6034c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 604f1220db8SAlexander V. Chernikov 605358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 606358b9d09SAlexander V. Chernikov if (arg == NULL) 607358b9d09SAlexander V. Chernikov return (0); 608358b9d09SAlexander V. Chernikov 6095f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 6105f379342SAlexander V. Chernikov return (0); 6115f379342SAlexander V. Chernikov tainfo = &i->ta_info; 6125f379342SAlexander V. Chernikov 6135f379342SAlexander V. Chernikov afdata = 0; 6145f379342SAlexander V. Chernikov afitem = 0; 6155f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 6165f379342SAlexander V. Chernikov afdata = 1; 6175f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 6185f379342SAlexander V. Chernikov afitem = 1; 6195f379342SAlexander V. Chernikov 6205f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 6215f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 6225f379342SAlexander V. Chernikov d.size = tainfo->size4; 6235f379342SAlexander V. Chernikov d.count = tainfo->count4; 6245f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 6255f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 6265f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 6275f379342SAlexander V. Chernikov else 6285f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 6295f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 6305f379342SAlexander V. Chernikov vtype = "unknown"; 6315f379342SAlexander V. Chernikov 6325f379342SAlexander V. Chernikov if (afdata == 0) { 6335f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 6345f379342SAlexander V. Chernikov } else { 6355f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 6365f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 6375f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 6385f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 6395f379342SAlexander V. Chernikov vtype = "unknown"; 6405f379342SAlexander V. Chernikov d.size = tainfo->size6; 6415f379342SAlexander V. Chernikov d.count = tainfo->count6; 6425f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 6435f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 6445f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 6455f379342SAlexander V. Chernikov } 6465f379342SAlexander V. Chernikov 647f1220db8SAlexander V. Chernikov return (0); 648f1220db8SAlexander V. Chernikov } 649f1220db8SAlexander V. Chernikov 650f1220db8SAlexander V. Chernikov 651f1220db8SAlexander V. Chernikov /* 652f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 653f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 654f1220db8SAlexander V. Chernikov */ 655f1220db8SAlexander V. Chernikov 656f1220db8SAlexander V. Chernikov static int 657f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 658f1220db8SAlexander V. Chernikov { 659f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 66081d3153dSAlexander V. Chernikov int error; 661f1220db8SAlexander V. Chernikov 662ac35ff17SAlexander V. Chernikov if ((oh = calloc(1, i->size)) == NULL) 663f1220db8SAlexander V. Chernikov return (ENOMEM); 664f1220db8SAlexander V. Chernikov 66581d3153dSAlexander V. Chernikov if ((error = table_get_list(i, oh)) != 0) { 66681d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 66781d3153dSAlexander V. Chernikov return (error); 66881d3153dSAlexander V. Chernikov } 66981d3153dSAlexander V. Chernikov 670f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 671f1220db8SAlexander V. Chernikov 672f1220db8SAlexander V. Chernikov free(oh); 673f1220db8SAlexander V. Chernikov return (0); 674f1220db8SAlexander V. Chernikov } 675f1220db8SAlexander V. Chernikov 676f1220db8SAlexander V. Chernikov static int 677f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 678f1220db8SAlexander V. Chernikov { 679ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 680f1220db8SAlexander V. Chernikov 681ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 682ac35ff17SAlexander V. Chernikov 683ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 684ac35ff17SAlexander V. Chernikov 685ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 686f1220db8SAlexander V. Chernikov } 687f1220db8SAlexander V. Chernikov 688ac35ff17SAlexander V. Chernikov static int 689ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 690ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 691ac35ff17SAlexander V. Chernikov { 692db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 693db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 694ac35ff17SAlexander V. Chernikov int error; 695ac35ff17SAlexander V. Chernikov 696ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 697ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 698ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 699ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 700ac35ff17SAlexander V. Chernikov 701db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 702db785d31SAlexander V. Chernikov ctlv->count = 1; 703db785d31SAlexander V. Chernikov ctlv->head.length = sizeof(*ctlv) + sizeof(*tent); 704db785d31SAlexander V. Chernikov 705db785d31SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent)); 706db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 707ac35ff17SAlexander V. Chernikov if (update != 0) 70881d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 709ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 710ac35ff17SAlexander V. Chernikov 711ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 712ac35ff17SAlexander V. Chernikov 713ac35ff17SAlexander V. Chernikov return (error); 714ac35ff17SAlexander V. Chernikov } 715ac35ff17SAlexander V. Chernikov 716ac35ff17SAlexander V. Chernikov static void 717ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 718ac35ff17SAlexander V. Chernikov { 719ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 72081d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 721ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 7224c0c07a5SAlexander V. Chernikov int cmd, error; 7234c0c07a5SAlexander V. Chernikov char *texterr, *etxt; 724ac35ff17SAlexander V. Chernikov 725ac35ff17SAlexander V. Chernikov if (ac == 0) 726ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 727ac35ff17SAlexander V. Chernikov 728ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 729ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 730ac35ff17SAlexander V. Chernikov tent.idx = 1; 731ac35ff17SAlexander V. Chernikov 73281d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 733db785d31SAlexander V. Chernikov 734db785d31SAlexander V. Chernikov /* 735db785d31SAlexander V. Chernikov * compability layer: auto-create table if not exists 736db785d31SAlexander V. Chernikov */ 737db785d31SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 738db785d31SAlexander V. Chernikov xi.type = type; 739db785d31SAlexander V. Chernikov xi.vtype = vtype; 740db785d31SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); 741db785d31SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info non-existent " 742db785d31SAlexander V. Chernikov "table %s. (auto-created)\n", xi.tablename); 743db785d31SAlexander V. Chernikov table_do_create(oh, &xi); 744db785d31SAlexander V. Chernikov } 745db785d31SAlexander V. Chernikov 746ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 747ac35ff17SAlexander V. Chernikov ac--; av++; 748ac35ff17SAlexander V. Chernikov 749ac35ff17SAlexander V. Chernikov if (add != 0) { 750ac35ff17SAlexander V. Chernikov if (ac > 0) 751ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 752ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 7534c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 754ac35ff17SAlexander V. Chernikov } else { 755ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 7564c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 757ac35ff17SAlexander V. Chernikov } 758ac35ff17SAlexander V. Chernikov 7594c0c07a5SAlexander V. Chernikov if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0) 7604c0c07a5SAlexander V. Chernikov return; 7614c0c07a5SAlexander V. Chernikov 7624c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 7634c0c07a5SAlexander V. Chernikov switch (error) { 7644c0c07a5SAlexander V. Chernikov case EEXIST: 7654c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 7664c0c07a5SAlexander V. Chernikov break; 7674c0c07a5SAlexander V. Chernikov case EFBIG: 7684c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 7694c0c07a5SAlexander V. Chernikov break; 7704c0c07a5SAlexander V. Chernikov case ESRCH: 7714c0c07a5SAlexander V. Chernikov etxt = "table not found"; 7724c0c07a5SAlexander V. Chernikov break; 7734c0c07a5SAlexander V. Chernikov case ENOENT: 7744c0c07a5SAlexander V. Chernikov etxt = "record not found"; 7754c0c07a5SAlexander V. Chernikov break; 7764c0c07a5SAlexander V. Chernikov default: 7774c0c07a5SAlexander V. Chernikov etxt = strerror(error); 7784c0c07a5SAlexander V. Chernikov } 7794c0c07a5SAlexander V. Chernikov 7804c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 781ac35ff17SAlexander V. Chernikov } 782ac35ff17SAlexander V. Chernikov 78381d3153dSAlexander V. Chernikov static int 78481d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 78581d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 78681d3153dSAlexander V. Chernikov { 78781d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 78881d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 78981d3153dSAlexander V. Chernikov uint8_t type, vtype; 79081d3153dSAlexander V. Chernikov int error; 79181d3153dSAlexander V. Chernikov size_t sz; 79281d3153dSAlexander V. Chernikov 79381d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 79481d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 79581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 79681d3153dSAlexander V. Chernikov 79781d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 79881d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 79981d3153dSAlexander V. Chernikov tent->idx = 1; 80081d3153dSAlexander V. Chernikov 80181d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 80281d3153dSAlexander V. Chernikov oh->ntlv.type = type; 80381d3153dSAlexander V. Chernikov 80481d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 80581d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 80681d3153dSAlexander V. Chernikov return (error); 80781d3153dSAlexander V. Chernikov 80881d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 80981d3153dSAlexander V. Chernikov return (EINVAL); 81081d3153dSAlexander V. Chernikov 81181d3153dSAlexander V. Chernikov *xtent = *tent; 81281d3153dSAlexander V. Chernikov 81381d3153dSAlexander V. Chernikov return (0); 81481d3153dSAlexander V. Chernikov } 81581d3153dSAlexander V. Chernikov 81681d3153dSAlexander V. Chernikov static void 81781d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 81881d3153dSAlexander V. Chernikov { 81981d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 82081d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 821914bffb6SAlexander V. Chernikov char key[64]; 82281d3153dSAlexander V. Chernikov int error; 82381d3153dSAlexander V. Chernikov 82481d3153dSAlexander V. Chernikov if (ac == 0) 82581d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 82681d3153dSAlexander V. Chernikov 827914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 828914bffb6SAlexander V. Chernikov 829914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 83081d3153dSAlexander V. Chernikov 83181d3153dSAlexander V. Chernikov switch (error) { 83281d3153dSAlexander V. Chernikov case 0: 83381d3153dSAlexander V. Chernikov break; 83481d3153dSAlexander V. Chernikov case ESRCH: 83581d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 83681d3153dSAlexander V. Chernikov case ENOENT: 83781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 83881d3153dSAlexander V. Chernikov case ENOTSUP: 83981d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 84081d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 84181d3153dSAlexander V. Chernikov default: 84281d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 84381d3153dSAlexander V. Chernikov } 84481d3153dSAlexander V. Chernikov 84581d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 84681d3153dSAlexander V. Chernikov } 847ac35ff17SAlexander V. Chernikov 848ac35ff17SAlexander V. Chernikov static void 849914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 850914bffb6SAlexander V. Chernikov uint8_t tflags) 851ac35ff17SAlexander V. Chernikov { 852914bffb6SAlexander V. Chernikov char *p, *pp; 853ac35ff17SAlexander V. Chernikov int mask, af; 854914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 855914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 856ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 857914bffb6SAlexander V. Chernikov uint16_t port; 858914bffb6SAlexander V. Chernikov struct protoent *pent; 859914bffb6SAlexander V. Chernikov struct servent *sent; 860ac35ff17SAlexander V. Chernikov int masklen; 861ac35ff17SAlexander V. Chernikov 862ac35ff17SAlexander V. Chernikov masklen = 0; 863ac35ff17SAlexander V. Chernikov af = 0; 864ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 865ac35ff17SAlexander V. Chernikov 866ac35ff17SAlexander V. Chernikov switch (type) { 867ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 868ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 869ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 870ac35ff17SAlexander V. Chernikov *p = '\0'; 871ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 872ac35ff17SAlexander V. Chernikov } 873ac35ff17SAlexander V. Chernikov 874ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 875ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 876ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 877ac35ff17SAlexander V. Chernikov p + 1); 878ac35ff17SAlexander V. Chernikov 879ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 880ac35ff17SAlexander V. Chernikov af = AF_INET; 881ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 882ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 883ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 884ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 885ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 886ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 887ac35ff17SAlexander V. Chernikov p + 1); 888ac35ff17SAlexander V. Chernikov 889ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 890ac35ff17SAlexander V. Chernikov af = AF_INET6; 891ac35ff17SAlexander V. Chernikov } else { 892ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 893ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 894ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 895ac35ff17SAlexander V. Chernikov 896ac35ff17SAlexander V. Chernikov masklen = 32; 897ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 898ac35ff17SAlexander V. Chernikov af = AF_INET; 899ac35ff17SAlexander V. Chernikov } 900ac35ff17SAlexander V. Chernikov break; 901ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 902ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 903ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 904ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 905ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 906ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 907ac35ff17SAlexander V. Chernikov break; 908b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 909ac35ff17SAlexander V. Chernikov /* Port or any other key */ 910ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 911ac35ff17SAlexander V. Chernikov if (*p != '\0') 912ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 913ac35ff17SAlexander V. Chernikov 914ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 915ac35ff17SAlexander V. Chernikov *pkey = key; 916ac35ff17SAlexander V. Chernikov masklen = 32; 917ac35ff17SAlexander V. Chernikov break; 918914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 919914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 920914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 921914bffb6SAlexander V. Chernikov af = 0; 922914bffb6SAlexander V. Chernikov 923914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 924914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 925914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 926914bffb6SAlexander V. Chernikov *p++ = '\0'; 927914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 928914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 929914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 930914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 931914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 932914bffb6SAlexander V. Chernikov af = AF_INET; 933914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 934914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 935914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 936914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 937914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 938914bffb6SAlexander V. Chernikov af = AF_INET6; 939914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 940914bffb6SAlexander V. Chernikov } 941914bffb6SAlexander V. Chernikov 942914bffb6SAlexander V. Chernikov arg = p; 943914bffb6SAlexander V. Chernikov } 944914bffb6SAlexander V. Chernikov 945914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 946914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 947914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 948914bffb6SAlexander V. Chernikov *p++ = '\0'; 949914bffb6SAlexander V. Chernikov 950914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 951914bffb6SAlexander V. Chernikov if (*pp != '\0') { 952914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 953914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 954914bffb6SAlexander V. Chernikov arg); 955914bffb6SAlexander V. Chernikov else 956914bffb6SAlexander V. Chernikov key = pent->p_proto; 957914bffb6SAlexander V. Chernikov } 958914bffb6SAlexander V. Chernikov 959914bffb6SAlexander V. Chernikov if (key > 255) 960914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 961914bffb6SAlexander V. Chernikov 962914bffb6SAlexander V. Chernikov tfe->proto = key; 963914bffb6SAlexander V. Chernikov 964914bffb6SAlexander V. Chernikov arg = p; 965914bffb6SAlexander V. Chernikov } 966914bffb6SAlexander V. Chernikov 967914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 968914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 969914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 970914bffb6SAlexander V. Chernikov *p++ = '\0'; 971914bffb6SAlexander V. Chernikov 972914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 973914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 974914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 975914bffb6SAlexander V. Chernikov arg); 976914bffb6SAlexander V. Chernikov else 977914bffb6SAlexander V. Chernikov key = sent->s_port; 978914bffb6SAlexander V. Chernikov } 979914bffb6SAlexander V. Chernikov 980914bffb6SAlexander V. Chernikov tfe->sport = port; 981914bffb6SAlexander V. Chernikov 982914bffb6SAlexander V. Chernikov arg = p; 983914bffb6SAlexander V. Chernikov } 984914bffb6SAlexander V. Chernikov 985914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 986914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 987914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 988914bffb6SAlexander V. Chernikov *p++ = '\0'; 989914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 990914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 991914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 992914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 993914bffb6SAlexander V. Chernikov "Inconsistent address family"); 994914bffb6SAlexander V. Chernikov af = AF_INET; 995914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 996914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 997914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 998914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 999914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1000914bffb6SAlexander V. Chernikov af = AF_INET6; 1001914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1002914bffb6SAlexander V. Chernikov } 1003914bffb6SAlexander V. Chernikov 1004914bffb6SAlexander V. Chernikov arg = p; 1005914bffb6SAlexander V. Chernikov } 1006914bffb6SAlexander V. Chernikov 1007914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1008914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1009914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1010914bffb6SAlexander V. Chernikov *p++ = '\0'; 1011914bffb6SAlexander V. Chernikov 1012914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1013914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1014914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1015914bffb6SAlexander V. Chernikov arg); 1016914bffb6SAlexander V. Chernikov else 1017914bffb6SAlexander V. Chernikov key = sent->s_port; 1018914bffb6SAlexander V. Chernikov } 1019914bffb6SAlexander V. Chernikov 1020914bffb6SAlexander V. Chernikov tfe->dport = port; 1021914bffb6SAlexander V. Chernikov 1022914bffb6SAlexander V. Chernikov arg = p; 1023914bffb6SAlexander V. Chernikov } 1024914bffb6SAlexander V. Chernikov 1025914bffb6SAlexander V. Chernikov tfe->af = af; 1026914bffb6SAlexander V. Chernikov 1027914bffb6SAlexander V. Chernikov break; 1028914bffb6SAlexander V. Chernikov 1029ac35ff17SAlexander V. Chernikov default: 1030ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1031ac35ff17SAlexander V. Chernikov } 1032ac35ff17SAlexander V. Chernikov 1033ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1034ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1035ac35ff17SAlexander V. Chernikov } 1036ac35ff17SAlexander V. Chernikov 1037ac35ff17SAlexander V. Chernikov static void 1038ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 103981d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 1040ac35ff17SAlexander V. Chernikov { 1041914bffb6SAlexander V. Chernikov uint8_t type, tflags, vtype; 1042ac35ff17SAlexander V. Chernikov int error; 1043db785d31SAlexander V. Chernikov char *del; 1044ac35ff17SAlexander V. Chernikov 1045ac35ff17SAlexander V. Chernikov type = 0; 1046914bffb6SAlexander V. Chernikov tflags = 0; 1047ac35ff17SAlexander V. Chernikov vtype = 0; 1048ac35ff17SAlexander V. Chernikov 104981d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 105081d3153dSAlexander V. Chernikov 105181d3153dSAlexander V. Chernikov if (error == 0) { 105281d3153dSAlexander V. Chernikov /* Table found. */ 105381d3153dSAlexander V. Chernikov type = xi->type; 1054914bffb6SAlexander V. Chernikov tflags = xi->tflags; 105581d3153dSAlexander V. Chernikov vtype = xi->vtype; 105681d3153dSAlexander V. Chernikov } else { 105781d3153dSAlexander V. Chernikov if (error != ESRCH) 105881d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 105981d3153dSAlexander V. Chernikov oh->ntlv.name); 1060ac35ff17SAlexander V. Chernikov /* 106181d3153dSAlexander V. Chernikov * Table does not exist. 106281d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 106381d3153dSAlexander V. Chernikov * before failing. 1064ac35ff17SAlexander V. Chernikov */ 1065db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 1066db785d31SAlexander V. Chernikov *del = '\0'; 1067ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 1068ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 1069ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 1070ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 1071ac35ff17SAlexander V. Chernikov /* 107281d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 107381d3153dSAlexander V. Chernikov * This should be changed for MFC. 1074ac35ff17SAlexander V. Chernikov */ 107581d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 107681d3153dSAlexander V. Chernikov } else { 107781d3153dSAlexander V. Chernikov /* Inknown key */ 107881d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1079db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 108081d3153dSAlexander V. Chernikov } 1081db785d31SAlexander V. Chernikov if (del != NULL) 1082db785d31SAlexander V. Chernikov *del = '/'; 1083ac35ff17SAlexander V. Chernikov } 1084ac35ff17SAlexander V. Chernikov 1085914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1086ac35ff17SAlexander V. Chernikov 1087ac35ff17SAlexander V. Chernikov *ptype = type; 1088ac35ff17SAlexander V. Chernikov *pvtype = vtype; 1089ac35ff17SAlexander V. Chernikov } 1090ac35ff17SAlexander V. Chernikov 1091ac35ff17SAlexander V. Chernikov static void 1092ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1093ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 1094ac35ff17SAlexander V. Chernikov { 1095ac35ff17SAlexander V. Chernikov int code; 1096ac35ff17SAlexander V. Chernikov char *p; 1097ac35ff17SAlexander V. Chernikov 1098ac35ff17SAlexander V. Chernikov switch (vtype) { 1099ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 1100ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1101ac35ff17SAlexander V. Chernikov if (*p != '\0') 1102ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 1103ac35ff17SAlexander V. Chernikov break; 1104ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 1105ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 1106ac35ff17SAlexander V. Chernikov break; 1107ac35ff17SAlexander V. Chernikov /* Try hostname */ 1108ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 1109ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 1110ac35ff17SAlexander V. Chernikov break; 1111ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1112ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 1113ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 1114ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 1115ac35ff17SAlexander V. Chernikov } else { 1116ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 1117ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 1118ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 1119ac35ff17SAlexander V. Chernikov } 1120ac35ff17SAlexander V. Chernikov tent->value = code; 1121ac35ff17SAlexander V. Chernikov break; 1122ac35ff17SAlexander V. Chernikov default: 1123ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 1124ac35ff17SAlexander V. Chernikov } 1125ac35ff17SAlexander V. Chernikov } 1126f1220db8SAlexander V. Chernikov 1127f1220db8SAlexander V. Chernikov /* 1128f1220db8SAlexander V. Chernikov * Compare table names. 1129f1220db8SAlexander V. Chernikov * Honor number comparison. 1130f1220db8SAlexander V. Chernikov */ 1131f1220db8SAlexander V. Chernikov static int 1132f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1133f1220db8SAlexander V. Chernikov { 1134f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1135f1220db8SAlexander V. Chernikov 1136f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1137f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1138f1220db8SAlexander V. Chernikov 113968394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1140f1220db8SAlexander V. Chernikov } 1141f1220db8SAlexander V. Chernikov 1142f1220db8SAlexander V. Chernikov /* 1143f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1144f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1145f1220db8SAlexander V. Chernikov * Returns 0 on success. 1146f1220db8SAlexander V. Chernikov */ 1147f1220db8SAlexander V. Chernikov static int 1148f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1149f1220db8SAlexander V. Chernikov { 1150f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 1151f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1152f1220db8SAlexander V. Chernikov size_t sz; 1153f1220db8SAlexander V. Chernikov int i, error; 1154f1220db8SAlexander V. Chernikov 1155f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 1156f1220db8SAlexander V. Chernikov sz = sizeof(req); 1157f1220db8SAlexander V. Chernikov 1158d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 1159f1220db8SAlexander V. Chernikov return (errno); 1160f1220db8SAlexander V. Chernikov 1161f1220db8SAlexander V. Chernikov sz = req.size; 1162f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1163f1220db8SAlexander V. Chernikov return (ENOMEM); 1164f1220db8SAlexander V. Chernikov 1165f1220db8SAlexander V. Chernikov olh->size = sz; 1166d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 1167f1220db8SAlexander V. Chernikov free(olh); 1168f1220db8SAlexander V. Chernikov return (errno); 1169f1220db8SAlexander V. Chernikov } 1170f1220db8SAlexander V. Chernikov 1171f1220db8SAlexander V. Chernikov if (sort != 0) 1172f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1173f1220db8SAlexander V. Chernikov 1174f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1175f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1176f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1177f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1178f1220db8SAlexander V. Chernikov } 1179f1220db8SAlexander V. Chernikov 1180f1220db8SAlexander V. Chernikov free(olh); 1181f1220db8SAlexander V. Chernikov 1182f1220db8SAlexander V. Chernikov return (0); 1183f1220db8SAlexander V. Chernikov } 1184f1220db8SAlexander V. Chernikov 1185f1220db8SAlexander V. Chernikov /* 1186f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1187d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 1188d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 1189f1220db8SAlexander V. Chernikov * 1190f1220db8SAlexander V. Chernikov * Returns 0 on success. 1191f1220db8SAlexander V. Chernikov */ 1192f1220db8SAlexander V. Chernikov static int 1193f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 1194f1220db8SAlexander V. Chernikov { 1195f1220db8SAlexander V. Chernikov size_t sz; 119681d3153dSAlexander V. Chernikov int error, c; 1197f1220db8SAlexander V. Chernikov 119881d3153dSAlexander V. Chernikov sz = 0; 119981d3153dSAlexander V. Chernikov for (c = 0; c < 3; c++) { 1200f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 120181d3153dSAlexander V. Chernikov if (sz < i->size) 1202f1220db8SAlexander V. Chernikov sz = i->size; 1203f1220db8SAlexander V. Chernikov 1204d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 120581d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1206d3a4f924SAlexander V. Chernikov 120781d3153dSAlexander V. Chernikov if (error != ENOMEM) 1208f1220db8SAlexander V. Chernikov return (errno); 120981d3153dSAlexander V. Chernikov } 1210f1220db8SAlexander V. Chernikov 121181d3153dSAlexander V. Chernikov return (ENOMEM); 1212f1220db8SAlexander V. Chernikov } 1213f1220db8SAlexander V. Chernikov 1214f1220db8SAlexander V. Chernikov /* 1215f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1216f1220db8SAlexander V. Chernikov */ 1217f1220db8SAlexander V. Chernikov static void 1218f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1219f1220db8SAlexander V. Chernikov { 122081d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 122181d3153dSAlexander V. Chernikov uint32_t count; 1222f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1223f1220db8SAlexander V. Chernikov 1224f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 122581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1226f1220db8SAlexander V. Chernikov 1227f1220db8SAlexander V. Chernikov if (need_header) 1228f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1229f1220db8SAlexander V. Chernikov 1230f1220db8SAlexander V. Chernikov count = i->count; 1231f1220db8SAlexander V. Chernikov while (count > 0) { 123281d3153dSAlexander V. Chernikov table_show_entry(i, tent); 123381d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 123481d3153dSAlexander V. Chernikov count--; 123581d3153dSAlexander V. Chernikov } 123681d3153dSAlexander V. Chernikov } 123781d3153dSAlexander V. Chernikov 123881d3153dSAlexander V. Chernikov static void 123981d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 124081d3153dSAlexander V. Chernikov { 1241914bffb6SAlexander V. Chernikov char *comma, tbuf[128], pval[32]; 1242914bffb6SAlexander V. Chernikov void *paddr; 124381d3153dSAlexander V. Chernikov uint32_t tval; 1244914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 124581d3153dSAlexander V. Chernikov 124681d3153dSAlexander V. Chernikov tval = tent->value; 124781d3153dSAlexander V. Chernikov 1248914bffb6SAlexander V. Chernikov if (co.do_value_as_ip) { 1249914bffb6SAlexander V. Chernikov tval = htonl(tval); 1250914bffb6SAlexander V. Chernikov inet_ntop(AF_INET, &tval, pval, sizeof(pval)); 1251914bffb6SAlexander V. Chernikov } else 1252914bffb6SAlexander V. Chernikov snprintf(pval, sizeof(pval), "%u", tval); 1253914bffb6SAlexander V. Chernikov 1254f1220db8SAlexander V. Chernikov switch (i->type) { 1255f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1256f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 125781d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1258914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1259f1220db8SAlexander V. Chernikov break; 1260f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1261f1220db8SAlexander V. Chernikov /* Interface names */ 1262914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1263b23d5de9SAlexander V. Chernikov break; 1264b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1265b23d5de9SAlexander V. Chernikov /* numbers */ 1266914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1267b23d5de9SAlexander V. Chernikov break; 1268914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1269914bffb6SAlexander V. Chernikov /* flows */ 1270914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1271914bffb6SAlexander V. Chernikov comma = ""; 1272914bffb6SAlexander V. Chernikov 1273914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1274914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1275914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1276914bffb6SAlexander V. Chernikov else 1277914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1278914bffb6SAlexander V. Chernikov 1279914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1280914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1281914bffb6SAlexander V. Chernikov comma = ","; 1282914bffb6SAlexander V. Chernikov } 1283914bffb6SAlexander V. Chernikov 1284914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1285914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1286914bffb6SAlexander V. Chernikov comma = ","; 1287914bffb6SAlexander V. Chernikov } 1288914bffb6SAlexander V. Chernikov 1289914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1290914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1291914bffb6SAlexander V. Chernikov comma = ","; 1292914bffb6SAlexander V. Chernikov } 1293914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1294914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1295914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1296914bffb6SAlexander V. Chernikov else 1297914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1298914bffb6SAlexander V. Chernikov 1299914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1300914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1301914bffb6SAlexander V. Chernikov comma = ","; 1302914bffb6SAlexander V. Chernikov } 1303914bffb6SAlexander V. Chernikov 1304914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1305914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1306914bffb6SAlexander V. Chernikov comma = ","; 1307914bffb6SAlexander V. Chernikov } 1308914bffb6SAlexander V. Chernikov 1309914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1310f1220db8SAlexander V. Chernikov } 1311f1220db8SAlexander V. Chernikov } 1312f1220db8SAlexander V. Chernikov 13139d099b4fSAlexander V. Chernikov static int 13149d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 13159d099b4fSAlexander V. Chernikov { 13169d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 13179d099b4fSAlexander V. Chernikov size_t sz; 13189d099b4fSAlexander V. Chernikov int error; 13199d099b4fSAlexander V. Chernikov 13209d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 13219d099b4fSAlexander V. Chernikov sz = sizeof(req); 13229d099b4fSAlexander V. Chernikov 13239d099b4fSAlexander V. Chernikov error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); 13249d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 13259d099b4fSAlexander V. Chernikov return (error); 13269d099b4fSAlexander V. Chernikov 13279d099b4fSAlexander V. Chernikov sz = req.size; 13289d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 13299d099b4fSAlexander V. Chernikov return (ENOMEM); 13309d099b4fSAlexander V. Chernikov 13319d099b4fSAlexander V. Chernikov olh->size = sz; 13329d099b4fSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { 13339d099b4fSAlexander V. Chernikov free(olh); 13349d099b4fSAlexander V. Chernikov return (error); 13359d099b4fSAlexander V. Chernikov } 13369d099b4fSAlexander V. Chernikov 13379d099b4fSAlexander V. Chernikov *polh = olh; 13389d099b4fSAlexander V. Chernikov return (0); 13399d099b4fSAlexander V. Chernikov } 13409d099b4fSAlexander V. Chernikov 13419d099b4fSAlexander V. Chernikov void 13429d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 13439d099b4fSAlexander V. Chernikov { 13449d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 13459d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 13469d099b4fSAlexander V. Chernikov int error, i; 13479d099b4fSAlexander V. Chernikov const char *atype; 13489d099b4fSAlexander V. Chernikov 13499d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 13509d099b4fSAlexander V. Chernikov if (error != 0) 13519d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 13529d099b4fSAlexander V. Chernikov 13539d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 13549d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 13559d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 13569d099b4fSAlexander V. Chernikov atype = "unknown"; 13578ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 13588ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 13599d099b4fSAlexander V. Chernikov 13609d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 13619d099b4fSAlexander V. Chernikov } 13629d099b4fSAlexander V. Chernikov 13639d099b4fSAlexander V. Chernikov free(olh); 13649d099b4fSAlexander V. Chernikov } 13659d099b4fSAlexander V. Chernikov 13666c2997ffSAlexander V. Chernikov int 13676c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 13686c2997ffSAlexander V. Chernikov { 13696c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 13706c2997ffSAlexander V. Chernikov 13716c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 13726c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 13736c2997ffSAlexander V. Chernikov 13746c2997ffSAlexander V. Chernikov if (a->set < b->set) 13756c2997ffSAlexander V. Chernikov return (-1); 13766c2997ffSAlexander V. Chernikov else if (a->set > b->set) 13776c2997ffSAlexander V. Chernikov return (1); 13786c2997ffSAlexander V. Chernikov 13796c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 13806c2997ffSAlexander V. Chernikov return (-1); 13816c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 13826c2997ffSAlexander V. Chernikov return (1); 13836c2997ffSAlexander V. Chernikov 13846c2997ffSAlexander V. Chernikov return (0); 13856c2997ffSAlexander V. Chernikov } 1386563b5ab1SAlexander V. Chernikov 1387563b5ab1SAlexander V. Chernikov int 13886c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1389563b5ab1SAlexander V. Chernikov { 1390563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1391563b5ab1SAlexander V. Chernikov uint16_t key; 1392563b5ab1SAlexander V. Chernikov 1393563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1394563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1395563b5ab1SAlexander V. Chernikov 1396563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1397563b5ab1SAlexander V. Chernikov return (-1); 1398563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1399563b5ab1SAlexander V. Chernikov return (1); 1400563b5ab1SAlexander V. Chernikov 1401563b5ab1SAlexander V. Chernikov return (0); 1402563b5ab1SAlexander V. Chernikov } 1403563b5ab1SAlexander V. Chernikov 1404563b5ab1SAlexander V. Chernikov /* 1405563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1406563b5ab1SAlexander V. Chernikov * Uses the following facts: 1407563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1408563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1409563b5ab1SAlexander V. Chernikov * 1410563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1411563b5ab1SAlexander V. Chernikov */ 1412563b5ab1SAlexander V. Chernikov char * 1413563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1414563b5ab1SAlexander V. Chernikov { 1415563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1416563b5ab1SAlexander V. Chernikov 1417563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 14186c2997ffSAlexander V. Chernikov compare_kntlv); 1419563b5ab1SAlexander V. Chernikov 1420563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1421563b5ab1SAlexander V. Chernikov return (ntlv->name); 1422563b5ab1SAlexander V. Chernikov 1423563b5ab1SAlexander V. Chernikov return (NULL); 1424563b5ab1SAlexander V. Chernikov } 1425563b5ab1SAlexander V. Chernikov 14266c2997ffSAlexander V. Chernikov void 14276c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 14286c2997ffSAlexander V. Chernikov { 14296c2997ffSAlexander V. Chernikov 14306c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 14316c2997ffSAlexander V. Chernikov } 14326c2997ffSAlexander V. Chernikov 14336c2997ffSAlexander V. Chernikov int 14346c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 14356c2997ffSAlexander V. Chernikov { 14366c2997ffSAlexander V. Chernikov int c, i, l; 14376c2997ffSAlexander V. Chernikov 14386c2997ffSAlexander V. Chernikov /* 14396c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 14406c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 1441ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 14426c2997ffSAlexander V. Chernikov */ 14436c2997ffSAlexander V. Chernikov l = strlen(tablename); 14446c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 14456c2997ffSAlexander V. Chernikov return (EINVAL); 14466c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 14476c2997ffSAlexander V. Chernikov c = tablename[i]; 14486c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 14496c2997ffSAlexander V. Chernikov c == '-' || c == '.') 14506c2997ffSAlexander V. Chernikov continue; 14516c2997ffSAlexander V. Chernikov return (EINVAL); 14526c2997ffSAlexander V. Chernikov } 14536c2997ffSAlexander V. Chernikov 1454ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1455ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1456ac35ff17SAlexander V. Chernikov return (EINVAL); 1457ac35ff17SAlexander V. Chernikov 14586c2997ffSAlexander V. Chernikov return (0); 14596c2997ffSAlexander V. Chernikov } 14606c2997ffSAlexander V. Chernikov 1461