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 }, 85ac35ff17SAlexander V. Chernikov { "u32", IPFW_TABLE_U32 }, 86ac35ff17SAlexander V. Chernikov { NULL, 0 } 87ac35ff17SAlexander V. Chernikov }; 88ac35ff17SAlexander V. Chernikov 89ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 90ac35ff17SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 91ac35ff17SAlexander V. Chernikov { "ip", IPFW_VTYPE_IP }, 92ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 93ac35ff17SAlexander V. Chernikov { NULL, 0 } 94ac35ff17SAlexander V. Chernikov }; 95ac35ff17SAlexander V. Chernikov 96ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 97ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 98ac35ff17SAlexander V. Chernikov { "create", TOK_CREATE }, 99ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 100ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 101ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 102ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 103ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 10481d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 105ac35ff17SAlexander V. Chernikov { NULL, 0 } 106ac35ff17SAlexander V. Chernikov }; 107ac35ff17SAlexander V. Chernikov 108f1220db8SAlexander V. Chernikov static int 109f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 110f1220db8SAlexander V. Chernikov { 111f1220db8SAlexander V. Chernikov struct hostent *he; 112f1220db8SAlexander V. Chernikov 113f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 114f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 115f1220db8SAlexander V. Chernikov return(-1); 116f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 117f1220db8SAlexander V. Chernikov } 118f1220db8SAlexander V. Chernikov return(0); 119f1220db8SAlexander V. Chernikov } 120f1220db8SAlexander V. Chernikov 121f1220db8SAlexander V. Chernikov /* 122f1220db8SAlexander V. Chernikov * This one handles all table-related commands 123ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 124ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 125ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 126ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 127ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 128ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 129ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 130f1220db8SAlexander V. Chernikov */ 131f1220db8SAlexander V. Chernikov void 132f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 133f1220db8SAlexander V. Chernikov { 134ac35ff17SAlexander V. Chernikov int do_add, is_all; 135ac35ff17SAlexander V. Chernikov int error, tcmd; 136ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 137ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 138f1220db8SAlexander V. Chernikov char *tablename; 139ac35ff17SAlexander V. Chernikov uint32_t set; 140f1220db8SAlexander V. Chernikov 141ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 142ac35ff17SAlexander V. Chernikov is_all = 0; 143ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 144ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 145ac35ff17SAlexander V. Chernikov else 146ac35ff17SAlexander V. Chernikov set = 0; 147f1220db8SAlexander V. Chernikov 148f1220db8SAlexander V. Chernikov ac--; av++; 149f1220db8SAlexander V. Chernikov tablename = *av; 150f1220db8SAlexander V. Chernikov 151ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 152ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 153ac35ff17SAlexander V. Chernikov oh.idx = 1; 154ac35ff17SAlexander V. Chernikov } else { 155ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 156ac35ff17SAlexander V. Chernikov is_all = 1; 157ac35ff17SAlexander V. Chernikov else 158ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 159ac35ff17SAlexander V. Chernikov } 160ac35ff17SAlexander V. Chernikov ac--; av++; 161ac35ff17SAlexander V. Chernikov 162ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 163ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 164ac35ff17SAlexander V. Chernikov 165ac35ff17SAlexander V. Chernikov NEED1("table needs command"); 166ac35ff17SAlexander V. Chernikov switch (tcmd) { 167ac35ff17SAlexander V. Chernikov case TOK_LIST: 168ac35ff17SAlexander V. Chernikov case TOK_INFO: 169ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 170ac35ff17SAlexander V. Chernikov break; 171ac35ff17SAlexander V. Chernikov default: 172ac35ff17SAlexander V. Chernikov if (is_all != 0) 173ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 174ac35ff17SAlexander V. Chernikov } 175ac35ff17SAlexander V. Chernikov 176ac35ff17SAlexander V. Chernikov switch (tcmd) { 177ac35ff17SAlexander V. Chernikov case TOK_ADD: 178ac35ff17SAlexander V. Chernikov case TOK_DEL: 179f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 180f1220db8SAlexander V. Chernikov ac--; av++; 181ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 182ac35ff17SAlexander V. Chernikov break; 183ac35ff17SAlexander V. Chernikov case TOK_CREATE: 184f1220db8SAlexander V. Chernikov ac--; av++; 185ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 186ac35ff17SAlexander V. Chernikov break; 187ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 188ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 189ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 190ac35ff17SAlexander V. Chernikov break; 191ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 192f1220db8SAlexander V. Chernikov if (is_all == 0) { 193ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 194f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 195f1220db8SAlexander V. Chernikov tablename); 196f1220db8SAlexander V. Chernikov } else { 197ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 198f1220db8SAlexander V. Chernikov if (error != 0) 199f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 200f1220db8SAlexander V. Chernikov } 201ac35ff17SAlexander V. Chernikov break; 202ac35ff17SAlexander V. Chernikov case TOK_INFO: 203f1220db8SAlexander V. Chernikov if (is_all == 0) { 204ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 205f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 206f1220db8SAlexander V. Chernikov table_show_info(&i, NULL); 207f1220db8SAlexander V. Chernikov } else { 208f1220db8SAlexander V. Chernikov error = tables_foreach(table_show_info, NULL, 1); 209f1220db8SAlexander V. Chernikov if (error != 0) 210f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 211f1220db8SAlexander V. Chernikov } 212ac35ff17SAlexander V. Chernikov break; 213ac35ff17SAlexander V. Chernikov case TOK_LIST: 214ac35ff17SAlexander V. Chernikov if (is_all == 0) { 215ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 216ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 217ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 218ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 219f1220db8SAlexander V. Chernikov } else { 220ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 221ac35ff17SAlexander V. Chernikov if (error != 0) 222ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 223f1220db8SAlexander V. Chernikov } 224ac35ff17SAlexander V. Chernikov break; 22581d3153dSAlexander V. Chernikov case TOK_LOOKUP: 22681d3153dSAlexander V. Chernikov ac--; av++; 22781d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 22881d3153dSAlexander V. Chernikov break; 229f1220db8SAlexander V. Chernikov } 230f1220db8SAlexander V. Chernikov } 231f1220db8SAlexander V. Chernikov 232f1220db8SAlexander V. Chernikov static void 233ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 234f1220db8SAlexander V. Chernikov { 235f1220db8SAlexander V. Chernikov 236563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 237f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 238f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 239ac35ff17SAlexander V. Chernikov ntlv->set = set; 240f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 241f1220db8SAlexander V. Chernikov } 242f1220db8SAlexander V. Chernikov 243f1220db8SAlexander V. Chernikov static void 244f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 245f1220db8SAlexander V. Chernikov { 246f1220db8SAlexander V. Chernikov 247f1220db8SAlexander V. Chernikov oh->idx = 1; 24881d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 249ac35ff17SAlexander V. Chernikov } 250ac35ff17SAlexander V. Chernikov 251ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 252ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE}, 253ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 254ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 255ac35ff17SAlexander V. Chernikov { NULL, 0 } 256ac35ff17SAlexander V. Chernikov }; 257ac35ff17SAlexander V. Chernikov 258ac35ff17SAlexander V. Chernikov /* 259ac35ff17SAlexander V. Chernikov * Creates new table 260ac35ff17SAlexander V. Chernikov * 261ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 262ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 263ac35ff17SAlexander V. Chernikov * [ algo algoname ] 264ac35ff17SAlexander V. Chernikov * 265ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 266ac35ff17SAlexander V. Chernikov */ 267ac35ff17SAlexander V. Chernikov static void 268ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 269ac35ff17SAlexander V. Chernikov { 270ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 271ac35ff17SAlexander V. Chernikov int error, tcmd, val; 272ac35ff17SAlexander V. Chernikov size_t sz; 273ac35ff17SAlexander V. Chernikov char tbuf[128]; 274ac35ff17SAlexander V. Chernikov 275ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 276ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 277ac35ff17SAlexander V. Chernikov 278ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 279ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 280ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 281ac35ff17SAlexander V. Chernikov 282ac35ff17SAlexander V. Chernikov while (ac > 0) { 283ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 284ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 285ac35ff17SAlexander V. Chernikov ac--; av++; 286ac35ff17SAlexander V. Chernikov 287ac35ff17SAlexander V. Chernikov switch (tcmd) { 288ac35ff17SAlexander V. Chernikov case TOK_TYPE: 289ac35ff17SAlexander V. Chernikov NEED1("table type required"); 290ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 291ac35ff17SAlexander V. Chernikov if (val != -1) { 292ac35ff17SAlexander V. Chernikov xi.type = val; 293ac35ff17SAlexander V. Chernikov ac--; av++; 294ac35ff17SAlexander V. Chernikov break; 295ac35ff17SAlexander V. Chernikov } 296ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", "); 297ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s", 298ac35ff17SAlexander V. Chernikov *av, tbuf); 299ac35ff17SAlexander V. Chernikov break; 300ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 301ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 302ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 303ac35ff17SAlexander V. Chernikov if (val != -1) { 304ac35ff17SAlexander V. Chernikov xi.vtype = val; 305ac35ff17SAlexander V. Chernikov ac--; av++; 306ac35ff17SAlexander V. Chernikov break; 307ac35ff17SAlexander V. Chernikov } 308ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 309ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 310ac35ff17SAlexander V. Chernikov *av, tbuf); 311ac35ff17SAlexander V. Chernikov break; 312ac35ff17SAlexander V. Chernikov case TOK_ALGO: 313ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 314ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 315ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 316ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 317ac35ff17SAlexander V. Chernikov ac--; av++; 318ac35ff17SAlexander V. Chernikov break; 319ac35ff17SAlexander V. Chernikov } 320ac35ff17SAlexander V. Chernikov } 321ac35ff17SAlexander V. Chernikov 322ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 323ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 324f1220db8SAlexander V. Chernikov } 325f1220db8SAlexander V. Chernikov 326f1220db8SAlexander V. Chernikov /* 327ac35ff17SAlexander V. Chernikov * Creates new table 328ac35ff17SAlexander V. Chernikov * 329ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 330ac35ff17SAlexander V. Chernikov * 331f1220db8SAlexander V. Chernikov * Returns 0 on success. 332f1220db8SAlexander V. Chernikov */ 333f1220db8SAlexander V. Chernikov static int 334ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 335f1220db8SAlexander V. Chernikov { 336ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 337ac35ff17SAlexander V. Chernikov int error; 338f1220db8SAlexander V. Chernikov 339ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 340ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 341ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 342ac35ff17SAlexander V. Chernikov 343ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 344ac35ff17SAlexander V. Chernikov 345ac35ff17SAlexander V. Chernikov return (error); 346ac35ff17SAlexander V. Chernikov } 347ac35ff17SAlexander V. Chernikov 348ac35ff17SAlexander V. Chernikov /* 349ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 350ac35ff17SAlexander V. Chernikov * Returns 0 on success. 351ac35ff17SAlexander V. Chernikov */ 352ac35ff17SAlexander V. Chernikov static int 353ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 354ac35ff17SAlexander V. Chernikov { 355ac35ff17SAlexander V. Chernikov 356ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 357f1220db8SAlexander V. Chernikov return (-1); 358f1220db8SAlexander V. Chernikov 359f1220db8SAlexander V. Chernikov return (0); 360f1220db8SAlexander V. Chernikov } 361f1220db8SAlexander V. Chernikov 362f1220db8SAlexander V. Chernikov /* 363ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 364f1220db8SAlexander V. Chernikov * Returns 0 on success. 365f1220db8SAlexander V. Chernikov */ 366f1220db8SAlexander V. Chernikov static int 367ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 368f1220db8SAlexander V. Chernikov { 369f1220db8SAlexander V. Chernikov 370ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 371f1220db8SAlexander V. Chernikov return (-1); 372f1220db8SAlexander V. Chernikov 373f1220db8SAlexander V. Chernikov return (0); 374f1220db8SAlexander V. Chernikov } 375f1220db8SAlexander V. Chernikov 376f1220db8SAlexander V. Chernikov /* 377ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 378f1220db8SAlexander V. Chernikov * it inside @i. 379f1220db8SAlexander V. Chernikov * Returns 0 on success. 380f1220db8SAlexander V. Chernikov */ 381f1220db8SAlexander V. Chernikov static int 382ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 383f1220db8SAlexander V. Chernikov { 384f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 385ac35ff17SAlexander V. Chernikov int error; 386f1220db8SAlexander V. Chernikov size_t sz; 387f1220db8SAlexander V. Chernikov 388f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 389f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 390ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 391f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 392f1220db8SAlexander V. Chernikov 393ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 394ac35ff17SAlexander V. Chernikov return (error); 395f1220db8SAlexander V. Chernikov 396f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 397ac35ff17SAlexander V. Chernikov return (EINVAL); 398f1220db8SAlexander V. Chernikov 399f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 400f1220db8SAlexander V. Chernikov 401f1220db8SAlexander V. Chernikov return (0); 402f1220db8SAlexander V. Chernikov } 403f1220db8SAlexander V. Chernikov 404f1220db8SAlexander V. Chernikov /* 405f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 406f1220db8SAlexander V. Chernikov */ 407f1220db8SAlexander V. Chernikov static int 408f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 409f1220db8SAlexander V. Chernikov { 410ac35ff17SAlexander V. Chernikov const char *ttype, *vtype; 411f1220db8SAlexander V. Chernikov 412f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 413ac35ff17SAlexander V. Chernikov if ((ttype = match_value(tabletypes, i->type)) == NULL) 414ac35ff17SAlexander V. Chernikov ttype = "unknown"; 415ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 416ac35ff17SAlexander V. Chernikov vtype = "unknown"; 417ac35ff17SAlexander V. Chernikov 418ac35ff17SAlexander V. Chernikov printf(" type: %s, kindex: %d\n", ttype, i->kidx); 419ac35ff17SAlexander V. Chernikov printf(" valtype: %s, algorithm: %s\n", vtype, i->algoname); 420f1220db8SAlexander V. Chernikov printf(" references: %u\n", i->refcnt); 421f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 422f1220db8SAlexander V. Chernikov 423f1220db8SAlexander V. Chernikov return (0); 424f1220db8SAlexander V. Chernikov } 425f1220db8SAlexander V. Chernikov 426f1220db8SAlexander V. Chernikov 427f1220db8SAlexander V. Chernikov /* 428f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 429f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 430f1220db8SAlexander V. Chernikov */ 431f1220db8SAlexander V. Chernikov 432f1220db8SAlexander V. Chernikov static int 433f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 434f1220db8SAlexander V. Chernikov { 435f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 43681d3153dSAlexander V. Chernikov int error; 437f1220db8SAlexander V. Chernikov 438ac35ff17SAlexander V. Chernikov if ((oh = calloc(1, i->size)) == NULL) 439f1220db8SAlexander V. Chernikov return (ENOMEM); 440f1220db8SAlexander V. Chernikov 44181d3153dSAlexander V. Chernikov if ((error = table_get_list(i, oh)) != 0) { 44281d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 44381d3153dSAlexander V. Chernikov return (error); 44481d3153dSAlexander V. Chernikov } 44581d3153dSAlexander V. Chernikov 446f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 447f1220db8SAlexander V. Chernikov 448f1220db8SAlexander V. Chernikov free(oh); 449f1220db8SAlexander V. Chernikov return (0); 450f1220db8SAlexander V. Chernikov } 451f1220db8SAlexander V. Chernikov 452f1220db8SAlexander V. Chernikov static int 453f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 454f1220db8SAlexander V. Chernikov { 455ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 456f1220db8SAlexander V. Chernikov 457ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 458ac35ff17SAlexander V. Chernikov 459ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 460ac35ff17SAlexander V. Chernikov 461ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 462f1220db8SAlexander V. Chernikov } 463f1220db8SAlexander V. Chernikov 464ac35ff17SAlexander V. Chernikov static int 465ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 466ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 467ac35ff17SAlexander V. Chernikov { 468*db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 469*db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 470ac35ff17SAlexander V. Chernikov int error; 471ac35ff17SAlexander V. Chernikov 472ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 473ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 474ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 475ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 476ac35ff17SAlexander V. Chernikov 477*db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 478*db785d31SAlexander V. Chernikov ctlv->count = 1; 479*db785d31SAlexander V. Chernikov ctlv->head.length = sizeof(*ctlv) + sizeof(*tent); 480*db785d31SAlexander V. Chernikov 481*db785d31SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent)); 482*db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 483ac35ff17SAlexander V. Chernikov if (update != 0) 48481d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 485ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 486ac35ff17SAlexander V. Chernikov 487ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 488ac35ff17SAlexander V. Chernikov 489ac35ff17SAlexander V. Chernikov return (error); 490ac35ff17SAlexander V. Chernikov } 491ac35ff17SAlexander V. Chernikov 492ac35ff17SAlexander V. Chernikov static void 493ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 494ac35ff17SAlexander V. Chernikov { 495ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 49681d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 497ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 498ac35ff17SAlexander V. Chernikov int cmd; 499ac35ff17SAlexander V. Chernikov char *texterr; 500ac35ff17SAlexander V. Chernikov 501ac35ff17SAlexander V. Chernikov if (ac == 0) 502ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 503ac35ff17SAlexander V. Chernikov 504ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 505ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 506ac35ff17SAlexander V. Chernikov tent.idx = 1; 507ac35ff17SAlexander V. Chernikov 50881d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 509*db785d31SAlexander V. Chernikov 510*db785d31SAlexander V. Chernikov /* 511*db785d31SAlexander V. Chernikov * compability layer: auto-create table if not exists 512*db785d31SAlexander V. Chernikov */ 513*db785d31SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 514*db785d31SAlexander V. Chernikov xi.type = type; 515*db785d31SAlexander V. Chernikov xi.vtype = vtype; 516*db785d31SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); 517*db785d31SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info non-existent " 518*db785d31SAlexander V. Chernikov "table %s. (auto-created)\n", xi.tablename); 519*db785d31SAlexander V. Chernikov table_do_create(oh, &xi); 520*db785d31SAlexander V. Chernikov } 521*db785d31SAlexander V. Chernikov 522ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 523ac35ff17SAlexander V. Chernikov ac--; av++; 524ac35ff17SAlexander V. Chernikov 525ac35ff17SAlexander V. Chernikov if (add != 0) { 526ac35ff17SAlexander V. Chernikov if (ac > 0) 527ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 528ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 529ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XADD)"; 530ac35ff17SAlexander V. Chernikov } else { 531ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 532ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XDEL)"; 533ac35ff17SAlexander V. Chernikov } 534ac35ff17SAlexander V. Chernikov 535ac35ff17SAlexander V. Chernikov if (table_do_modify_record(cmd, oh, &tent, update) != 0) 536ac35ff17SAlexander V. Chernikov err(EX_OSERR, "%s", texterr); 537ac35ff17SAlexander V. Chernikov } 538ac35ff17SAlexander V. Chernikov 53981d3153dSAlexander V. Chernikov static int 54081d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 54181d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 54281d3153dSAlexander V. Chernikov { 54381d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 54481d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 54581d3153dSAlexander V. Chernikov uint8_t type, vtype; 54681d3153dSAlexander V. Chernikov int error; 54781d3153dSAlexander V. Chernikov size_t sz; 54881d3153dSAlexander V. Chernikov 54981d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 55081d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 55181d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 55281d3153dSAlexander V. Chernikov 55381d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 55481d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 55581d3153dSAlexander V. Chernikov tent->idx = 1; 55681d3153dSAlexander V. Chernikov 55781d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 55881d3153dSAlexander V. Chernikov oh->ntlv.type = type; 55981d3153dSAlexander V. Chernikov 56081d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 56181d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 56281d3153dSAlexander V. Chernikov return (error); 56381d3153dSAlexander V. Chernikov 56481d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 56581d3153dSAlexander V. Chernikov return (EINVAL); 56681d3153dSAlexander V. Chernikov 56781d3153dSAlexander V. Chernikov *xtent = *tent; 56881d3153dSAlexander V. Chernikov 56981d3153dSAlexander V. Chernikov return (0); 57081d3153dSAlexander V. Chernikov } 57181d3153dSAlexander V. Chernikov 57281d3153dSAlexander V. Chernikov static void 57381d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 57481d3153dSAlexander V. Chernikov { 57581d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 57681d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 57781d3153dSAlexander V. Chernikov int error; 57881d3153dSAlexander V. Chernikov 57981d3153dSAlexander V. Chernikov if (ac == 0) 58081d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 58181d3153dSAlexander V. Chernikov 58281d3153dSAlexander V. Chernikov error = table_do_lookup(oh, *av, &xi, &xtent); 58381d3153dSAlexander V. Chernikov 58481d3153dSAlexander V. Chernikov switch (error) { 58581d3153dSAlexander V. Chernikov case 0: 58681d3153dSAlexander V. Chernikov break; 58781d3153dSAlexander V. Chernikov case ESRCH: 58881d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 58981d3153dSAlexander V. Chernikov case ENOENT: 59081d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 59181d3153dSAlexander V. Chernikov case ENOTSUP: 59281d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 59381d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 59481d3153dSAlexander V. Chernikov default: 59581d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 59681d3153dSAlexander V. Chernikov } 59781d3153dSAlexander V. Chernikov 59881d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 59981d3153dSAlexander V. Chernikov } 600ac35ff17SAlexander V. Chernikov 601ac35ff17SAlexander V. Chernikov static void 602ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type) 603ac35ff17SAlexander V. Chernikov { 604ac35ff17SAlexander V. Chernikov char *p; 605ac35ff17SAlexander V. Chernikov int mask, af; 606ac35ff17SAlexander V. Chernikov struct in6_addr *paddr; 607ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 608ac35ff17SAlexander V. Chernikov int masklen; 609ac35ff17SAlexander V. Chernikov 610ac35ff17SAlexander V. Chernikov masklen = 0; 611ac35ff17SAlexander V. Chernikov af = 0; 612ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 613ac35ff17SAlexander V. Chernikov 614ac35ff17SAlexander V. Chernikov switch (type) { 615ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 616ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 617ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 618ac35ff17SAlexander V. Chernikov *p = '\0'; 619ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 620ac35ff17SAlexander V. Chernikov } 621ac35ff17SAlexander V. Chernikov 622ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 623ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 624ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 625ac35ff17SAlexander V. Chernikov p + 1); 626ac35ff17SAlexander V. Chernikov 627ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 628ac35ff17SAlexander V. Chernikov af = AF_INET; 629ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 630ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 631ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 632ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 633ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 634ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 635ac35ff17SAlexander V. Chernikov p + 1); 636ac35ff17SAlexander V. Chernikov 637ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 638ac35ff17SAlexander V. Chernikov af = AF_INET6; 639ac35ff17SAlexander V. Chernikov } else { 640ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 641ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 642ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 643ac35ff17SAlexander V. Chernikov 644ac35ff17SAlexander V. Chernikov masklen = 32; 645ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 646ac35ff17SAlexander V. Chernikov af = AF_INET; 647ac35ff17SAlexander V. Chernikov } 648ac35ff17SAlexander V. Chernikov break; 649ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 650ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 651ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 652ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 653ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 654ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 655ac35ff17SAlexander V. Chernikov break; 656ac35ff17SAlexander V. Chernikov case IPFW_TABLE_U32: 657ac35ff17SAlexander V. Chernikov /* Port or any other key */ 658ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 659ac35ff17SAlexander V. Chernikov if (*p != '\0') 660ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 661ac35ff17SAlexander V. Chernikov 662ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 663ac35ff17SAlexander V. Chernikov *pkey = key; 664ac35ff17SAlexander V. Chernikov masklen = 32; 665ac35ff17SAlexander V. Chernikov break; 666ac35ff17SAlexander V. Chernikov default: 667ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 668ac35ff17SAlexander V. Chernikov } 669ac35ff17SAlexander V. Chernikov 670ac35ff17SAlexander V. Chernikov tentry->subtype = af; 671ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 672ac35ff17SAlexander V. Chernikov } 673ac35ff17SAlexander V. Chernikov 674ac35ff17SAlexander V. Chernikov static void 675ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 67681d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 677ac35ff17SAlexander V. Chernikov { 678ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 679ac35ff17SAlexander V. Chernikov int error; 680*db785d31SAlexander V. Chernikov char *del; 681ac35ff17SAlexander V. Chernikov 682ac35ff17SAlexander V. Chernikov type = 0; 683ac35ff17SAlexander V. Chernikov vtype = 0; 684ac35ff17SAlexander V. Chernikov 68581d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 68681d3153dSAlexander V. Chernikov 68781d3153dSAlexander V. Chernikov if (error == 0) { 68881d3153dSAlexander V. Chernikov /* Table found. */ 68981d3153dSAlexander V. Chernikov type = xi->type; 69081d3153dSAlexander V. Chernikov vtype = xi->vtype; 69181d3153dSAlexander V. Chernikov } else { 69281d3153dSAlexander V. Chernikov if (error != ESRCH) 69381d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 69481d3153dSAlexander V. Chernikov oh->ntlv.name); 695ac35ff17SAlexander V. Chernikov /* 69681d3153dSAlexander V. Chernikov * Table does not exist. 69781d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 69881d3153dSAlexander V. Chernikov * before failing. 699ac35ff17SAlexander V. Chernikov */ 700*db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 701*db785d31SAlexander V. Chernikov *del = '\0'; 702ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 703ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 704ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 705ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 706ac35ff17SAlexander V. Chernikov /* 70781d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 70881d3153dSAlexander V. Chernikov * This should be changed for MFC. 709ac35ff17SAlexander V. Chernikov */ 71081d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 71181d3153dSAlexander V. Chernikov } else { 71281d3153dSAlexander V. Chernikov /* Inknown key */ 71381d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 714*db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 71581d3153dSAlexander V. Chernikov } 716*db785d31SAlexander V. Chernikov if (del != NULL) 717*db785d31SAlexander V. Chernikov *del = '/'; 718ac35ff17SAlexander V. Chernikov } 719ac35ff17SAlexander V. Chernikov 720ac35ff17SAlexander V. Chernikov tentry_fill_key_type(key, tent, type); 721ac35ff17SAlexander V. Chernikov 722ac35ff17SAlexander V. Chernikov *ptype = type; 723ac35ff17SAlexander V. Chernikov *pvtype = vtype; 724ac35ff17SAlexander V. Chernikov } 725ac35ff17SAlexander V. Chernikov 726ac35ff17SAlexander V. Chernikov static void 727ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 728ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 729ac35ff17SAlexander V. Chernikov { 730ac35ff17SAlexander V. Chernikov int code; 731ac35ff17SAlexander V. Chernikov char *p; 732ac35ff17SAlexander V. Chernikov 733ac35ff17SAlexander V. Chernikov switch (vtype) { 734ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 735ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 736ac35ff17SAlexander V. Chernikov if (*p != '\0') 737ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 738ac35ff17SAlexander V. Chernikov break; 739ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 740ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 741ac35ff17SAlexander V. Chernikov break; 742ac35ff17SAlexander V. Chernikov /* Try hostname */ 743ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 744ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 745ac35ff17SAlexander V. Chernikov break; 746ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 747ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 748ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 749ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 750ac35ff17SAlexander V. Chernikov } else { 751ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 752ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 753ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 754ac35ff17SAlexander V. Chernikov } 755ac35ff17SAlexander V. Chernikov tent->value = code; 756ac35ff17SAlexander V. Chernikov break; 757ac35ff17SAlexander V. Chernikov default: 758ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 759ac35ff17SAlexander V. Chernikov } 760ac35ff17SAlexander V. Chernikov } 761f1220db8SAlexander V. Chernikov 762f1220db8SAlexander V. Chernikov /* 763f1220db8SAlexander V. Chernikov * Compare table names. 764f1220db8SAlexander V. Chernikov * Honor number comparison. 765f1220db8SAlexander V. Chernikov */ 766f1220db8SAlexander V. Chernikov static int 767f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 768f1220db8SAlexander V. Chernikov { 769f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 770f1220db8SAlexander V. Chernikov int la, lb; 771f1220db8SAlexander V. Chernikov 772f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 773f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 774f1220db8SAlexander V. Chernikov la = strlen(ia->tablename); 775f1220db8SAlexander V. Chernikov lb = strlen(ib->tablename); 776f1220db8SAlexander V. Chernikov 777f1220db8SAlexander V. Chernikov if (la > lb) 778f1220db8SAlexander V. Chernikov return (1); 779f1220db8SAlexander V. Chernikov else if (la < lb) 780f1220db8SAlexander V. Chernikov return (-01); 781f1220db8SAlexander V. Chernikov 782f1220db8SAlexander V. Chernikov return (strcmp(ia->tablename, ib->tablename)); 783f1220db8SAlexander V. Chernikov } 784f1220db8SAlexander V. Chernikov 785f1220db8SAlexander V. Chernikov /* 786f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 787f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 788f1220db8SAlexander V. Chernikov * Returns 0 on success. 789f1220db8SAlexander V. Chernikov */ 790f1220db8SAlexander V. Chernikov static int 791f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 792f1220db8SAlexander V. Chernikov { 793f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 794f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 795f1220db8SAlexander V. Chernikov size_t sz; 796f1220db8SAlexander V. Chernikov int i, error; 797f1220db8SAlexander V. Chernikov 798f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 799f1220db8SAlexander V. Chernikov sz = sizeof(req); 800f1220db8SAlexander V. Chernikov 801d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 802f1220db8SAlexander V. Chernikov return (errno); 803f1220db8SAlexander V. Chernikov 804f1220db8SAlexander V. Chernikov sz = req.size; 805f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 806f1220db8SAlexander V. Chernikov return (ENOMEM); 807f1220db8SAlexander V. Chernikov 808f1220db8SAlexander V. Chernikov olh->size = sz; 809d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 810f1220db8SAlexander V. Chernikov free(olh); 811f1220db8SAlexander V. Chernikov return (errno); 812f1220db8SAlexander V. Chernikov } 813f1220db8SAlexander V. Chernikov 814f1220db8SAlexander V. Chernikov if (sort != 0) 815f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 816f1220db8SAlexander V. Chernikov 817f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 818f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 819f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 820f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 821f1220db8SAlexander V. Chernikov } 822f1220db8SAlexander V. Chernikov 823f1220db8SAlexander V. Chernikov free(olh); 824f1220db8SAlexander V. Chernikov 825f1220db8SAlexander V. Chernikov return (0); 826f1220db8SAlexander V. Chernikov } 827f1220db8SAlexander V. Chernikov 828f1220db8SAlexander V. Chernikov /* 829f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 830d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 831d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 832f1220db8SAlexander V. Chernikov * 833f1220db8SAlexander V. Chernikov * Returns 0 on success. 834f1220db8SAlexander V. Chernikov */ 835f1220db8SAlexander V. Chernikov static int 836f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 837f1220db8SAlexander V. Chernikov { 838f1220db8SAlexander V. Chernikov size_t sz; 83981d3153dSAlexander V. Chernikov int error, c; 840f1220db8SAlexander V. Chernikov 84181d3153dSAlexander V. Chernikov sz = 0; 84281d3153dSAlexander V. Chernikov for (c = 0; c < 3; c++) { 843f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 84481d3153dSAlexander V. Chernikov if (sz < i->size) 845f1220db8SAlexander V. Chernikov sz = i->size; 846f1220db8SAlexander V. Chernikov 847d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 84881d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 849d3a4f924SAlexander V. Chernikov 85081d3153dSAlexander V. Chernikov if (error != ENOMEM) 851f1220db8SAlexander V. Chernikov return (errno); 85281d3153dSAlexander V. Chernikov } 853f1220db8SAlexander V. Chernikov 85481d3153dSAlexander V. Chernikov return (ENOMEM); 855f1220db8SAlexander V. Chernikov } 856f1220db8SAlexander V. Chernikov 857f1220db8SAlexander V. Chernikov /* 858f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 859f1220db8SAlexander V. Chernikov */ 860f1220db8SAlexander V. Chernikov static void 861f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 862f1220db8SAlexander V. Chernikov { 86381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 86481d3153dSAlexander V. Chernikov uint32_t count; 865f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 866f1220db8SAlexander V. Chernikov 867f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 86881d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 869f1220db8SAlexander V. Chernikov 870f1220db8SAlexander V. Chernikov if (need_header) 871f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 872f1220db8SAlexander V. Chernikov 873f1220db8SAlexander V. Chernikov count = i->count; 874f1220db8SAlexander V. Chernikov while (count > 0) { 87581d3153dSAlexander V. Chernikov table_show_entry(i, tent); 87681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 87781d3153dSAlexander V. Chernikov count--; 87881d3153dSAlexander V. Chernikov } 87981d3153dSAlexander V. Chernikov } 88081d3153dSAlexander V. Chernikov 88181d3153dSAlexander V. Chernikov static void 88281d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 88381d3153dSAlexander V. Chernikov { 88481d3153dSAlexander V. Chernikov char tbuf[128]; 88581d3153dSAlexander V. Chernikov uint32_t tval; 88681d3153dSAlexander V. Chernikov 88781d3153dSAlexander V. Chernikov tval = tent->value; 88881d3153dSAlexander V. Chernikov 889f1220db8SAlexander V. Chernikov switch (i->type) { 890f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 891f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 89281d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 893f1220db8SAlexander V. Chernikov 894f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 895f1220db8SAlexander V. Chernikov tval = htonl(tval); 89681d3153dSAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, 897f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 898f1220db8SAlexander V. Chernikov } else 89981d3153dSAlexander V. Chernikov printf("%s/%u %u\n", tbuf, tent->masklen, tval); 900f1220db8SAlexander V. Chernikov break; 901f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 902f1220db8SAlexander V. Chernikov /* Interface names */ 903f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 904f1220db8SAlexander V. Chernikov tval = htonl(tval); 90581d3153dSAlexander V. Chernikov printf("%s %s\n", tent->k.iface, 906f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 907f1220db8SAlexander V. Chernikov } else 90881d3153dSAlexander V. Chernikov printf("%s %u\n", tent->k.iface, tval); 909f1220db8SAlexander V. Chernikov } 910f1220db8SAlexander V. Chernikov } 911f1220db8SAlexander V. Chernikov 9126c2997ffSAlexander V. Chernikov int 9136c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 9146c2997ffSAlexander V. Chernikov { 9156c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 9166c2997ffSAlexander V. Chernikov 9176c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 9186c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 9196c2997ffSAlexander V. Chernikov 9206c2997ffSAlexander V. Chernikov if (a->set < b->set) 9216c2997ffSAlexander V. Chernikov return (-1); 9226c2997ffSAlexander V. Chernikov else if (a->set > b->set) 9236c2997ffSAlexander V. Chernikov return (1); 9246c2997ffSAlexander V. Chernikov 9256c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 9266c2997ffSAlexander V. Chernikov return (-1); 9276c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 9286c2997ffSAlexander V. Chernikov return (1); 9296c2997ffSAlexander V. Chernikov 9306c2997ffSAlexander V. Chernikov return (0); 9316c2997ffSAlexander V. Chernikov } 932563b5ab1SAlexander V. Chernikov 933563b5ab1SAlexander V. Chernikov int 9346c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 935563b5ab1SAlexander V. Chernikov { 936563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 937563b5ab1SAlexander V. Chernikov uint16_t key; 938563b5ab1SAlexander V. Chernikov 939563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 940563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 941563b5ab1SAlexander V. Chernikov 942563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 943563b5ab1SAlexander V. Chernikov return (-1); 944563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 945563b5ab1SAlexander V. Chernikov return (1); 946563b5ab1SAlexander V. Chernikov 947563b5ab1SAlexander V. Chernikov return (0); 948563b5ab1SAlexander V. Chernikov } 949563b5ab1SAlexander V. Chernikov 950563b5ab1SAlexander V. Chernikov /* 951563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 952563b5ab1SAlexander V. Chernikov * Uses the following facts: 953563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 954563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 955563b5ab1SAlexander V. Chernikov * 956563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 957563b5ab1SAlexander V. Chernikov */ 958563b5ab1SAlexander V. Chernikov char * 959563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 960563b5ab1SAlexander V. Chernikov { 961563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 962563b5ab1SAlexander V. Chernikov 963563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 9646c2997ffSAlexander V. Chernikov compare_kntlv); 965563b5ab1SAlexander V. Chernikov 966563b5ab1SAlexander V. Chernikov if (ntlv != 0) 967563b5ab1SAlexander V. Chernikov return (ntlv->name); 968563b5ab1SAlexander V. Chernikov 969563b5ab1SAlexander V. Chernikov return (NULL); 970563b5ab1SAlexander V. Chernikov } 971563b5ab1SAlexander V. Chernikov 9726c2997ffSAlexander V. Chernikov void 9736c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 9746c2997ffSAlexander V. Chernikov { 9756c2997ffSAlexander V. Chernikov 9766c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 9776c2997ffSAlexander V. Chernikov } 9786c2997ffSAlexander V. Chernikov 9796c2997ffSAlexander V. Chernikov int 9806c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 9816c2997ffSAlexander V. Chernikov { 9826c2997ffSAlexander V. Chernikov int c, i, l; 9836c2997ffSAlexander V. Chernikov 9846c2997ffSAlexander V. Chernikov /* 9856c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 9866c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 987ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 9886c2997ffSAlexander V. Chernikov */ 9896c2997ffSAlexander V. Chernikov l = strlen(tablename); 9906c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 9916c2997ffSAlexander V. Chernikov return (EINVAL); 9926c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 9936c2997ffSAlexander V. Chernikov c = tablename[i]; 9946c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 9956c2997ffSAlexander V. Chernikov c == '-' || c == '.') 9966c2997ffSAlexander V. Chernikov continue; 9976c2997ffSAlexander V. Chernikov return (EINVAL); 9986c2997ffSAlexander V. Chernikov } 9996c2997ffSAlexander V. Chernikov 1000ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1001ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1002ac35ff17SAlexander V. Chernikov return (EINVAL); 1003ac35ff17SAlexander V. Chernikov 10046c2997ffSAlexander V. Chernikov return (0); 10056c2997ffSAlexander V. Chernikov } 10066c2997ffSAlexander V. Chernikov 1007