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 { 468ac35ff17SAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 469ac35ff17SAlexander V. Chernikov int error; 470ac35ff17SAlexander V. Chernikov 471ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 472ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 473ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 474ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 475ac35ff17SAlexander V. Chernikov 476ac35ff17SAlexander V. Chernikov memcpy(oh + 1, tent, sizeof(*tent)); 477ac35ff17SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 478ac35ff17SAlexander V. Chernikov if (update != 0) 47981d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 480ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 481ac35ff17SAlexander V. Chernikov 482ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 483ac35ff17SAlexander V. Chernikov 484ac35ff17SAlexander V. Chernikov return (error); 485ac35ff17SAlexander V. Chernikov } 486ac35ff17SAlexander V. Chernikov 487ac35ff17SAlexander V. Chernikov static void 488ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 489ac35ff17SAlexander V. Chernikov { 490ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 49181d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 492ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 493ac35ff17SAlexander V. Chernikov int cmd; 494ac35ff17SAlexander V. Chernikov char *texterr; 495ac35ff17SAlexander V. Chernikov 496ac35ff17SAlexander V. Chernikov if (ac == 0) 497ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 498ac35ff17SAlexander V. Chernikov 499ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 500ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 501ac35ff17SAlexander V. Chernikov tent.idx = 1; 502ac35ff17SAlexander V. Chernikov 50381d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 504ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 505ac35ff17SAlexander V. Chernikov ac--; av++; 506ac35ff17SAlexander V. Chernikov 507ac35ff17SAlexander V. Chernikov if (add != 0) { 508ac35ff17SAlexander V. Chernikov if (ac > 0) 509ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 510ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 511ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XADD)"; 512ac35ff17SAlexander V. Chernikov } else { 513ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 514ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XDEL)"; 515ac35ff17SAlexander V. Chernikov } 516ac35ff17SAlexander V. Chernikov 517ac35ff17SAlexander V. Chernikov if (table_do_modify_record(cmd, oh, &tent, update) != 0) 518ac35ff17SAlexander V. Chernikov err(EX_OSERR, "%s", texterr); 519ac35ff17SAlexander V. Chernikov } 520ac35ff17SAlexander V. Chernikov 52181d3153dSAlexander V. Chernikov static int 52281d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 52381d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 52481d3153dSAlexander V. Chernikov { 52581d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 52681d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 52781d3153dSAlexander V. Chernikov uint8_t type, vtype; 52881d3153dSAlexander V. Chernikov int error; 52981d3153dSAlexander V. Chernikov size_t sz; 53081d3153dSAlexander V. Chernikov 53181d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 53281d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 53381d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 53481d3153dSAlexander V. Chernikov 53581d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 53681d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 53781d3153dSAlexander V. Chernikov tent->idx = 1; 53881d3153dSAlexander V. Chernikov 53981d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 54081d3153dSAlexander V. Chernikov oh->ntlv.type = type; 54181d3153dSAlexander V. Chernikov 54281d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 54381d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 54481d3153dSAlexander V. Chernikov return (error); 54581d3153dSAlexander V. Chernikov 54681d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 54781d3153dSAlexander V. Chernikov return (EINVAL); 54881d3153dSAlexander V. Chernikov 54981d3153dSAlexander V. Chernikov *xtent = *tent; 55081d3153dSAlexander V. Chernikov 55181d3153dSAlexander V. Chernikov return (0); 55281d3153dSAlexander V. Chernikov } 55381d3153dSAlexander V. Chernikov 55481d3153dSAlexander V. Chernikov static void 55581d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 55681d3153dSAlexander V. Chernikov { 55781d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 55881d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 55981d3153dSAlexander V. Chernikov int error; 56081d3153dSAlexander V. Chernikov 56181d3153dSAlexander V. Chernikov if (ac == 0) 56281d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 56381d3153dSAlexander V. Chernikov 56481d3153dSAlexander V. Chernikov error = table_do_lookup(oh, *av, &xi, &xtent); 56581d3153dSAlexander V. Chernikov 56681d3153dSAlexander V. Chernikov switch (error) { 56781d3153dSAlexander V. Chernikov case 0: 56881d3153dSAlexander V. Chernikov break; 56981d3153dSAlexander V. Chernikov case ESRCH: 57081d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 57181d3153dSAlexander V. Chernikov case ENOENT: 57281d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 57381d3153dSAlexander V. Chernikov case ENOTSUP: 57481d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 57581d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 57681d3153dSAlexander V. Chernikov default: 57781d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 57881d3153dSAlexander V. Chernikov } 57981d3153dSAlexander V. Chernikov 58081d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 58181d3153dSAlexander V. Chernikov } 582ac35ff17SAlexander V. Chernikov 583ac35ff17SAlexander V. Chernikov static void 584ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type) 585ac35ff17SAlexander V. Chernikov { 586ac35ff17SAlexander V. Chernikov char *p; 587ac35ff17SAlexander V. Chernikov int mask, af; 588ac35ff17SAlexander V. Chernikov struct in6_addr *paddr; 589ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 590ac35ff17SAlexander V. Chernikov int masklen; 591ac35ff17SAlexander V. Chernikov 592ac35ff17SAlexander V. Chernikov masklen = 0; 593ac35ff17SAlexander V. Chernikov af = 0; 594ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 595ac35ff17SAlexander V. Chernikov 596ac35ff17SAlexander V. Chernikov switch (type) { 597ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 598ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 599ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 600ac35ff17SAlexander V. Chernikov *p = '\0'; 601ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 602ac35ff17SAlexander V. Chernikov } 603ac35ff17SAlexander V. Chernikov 604ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 605ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 606ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 607ac35ff17SAlexander V. Chernikov p + 1); 608ac35ff17SAlexander V. Chernikov 609ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 610ac35ff17SAlexander V. Chernikov af = AF_INET; 611ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 612ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 613ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 614ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 615ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 616ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 617ac35ff17SAlexander V. Chernikov p + 1); 618ac35ff17SAlexander V. Chernikov 619ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 620ac35ff17SAlexander V. Chernikov af = AF_INET6; 621ac35ff17SAlexander V. Chernikov } else { 622ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 623ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 624ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 625ac35ff17SAlexander V. Chernikov 626ac35ff17SAlexander V. Chernikov masklen = 32; 627ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 628ac35ff17SAlexander V. Chernikov af = AF_INET; 629ac35ff17SAlexander V. Chernikov } 630ac35ff17SAlexander V. Chernikov break; 631ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 632ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 633ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 634ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 635ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 636ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 637ac35ff17SAlexander V. Chernikov break; 638ac35ff17SAlexander V. Chernikov case IPFW_TABLE_U32: 639ac35ff17SAlexander V. Chernikov /* Port or any other key */ 640ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 641ac35ff17SAlexander V. Chernikov if (*p != '\0') 642ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 643ac35ff17SAlexander V. Chernikov 644ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 645ac35ff17SAlexander V. Chernikov *pkey = key; 646ac35ff17SAlexander V. Chernikov masklen = 32; 647ac35ff17SAlexander V. Chernikov break; 648ac35ff17SAlexander V. Chernikov default: 649ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 650ac35ff17SAlexander V. Chernikov } 651ac35ff17SAlexander V. Chernikov 652ac35ff17SAlexander V. Chernikov tentry->subtype = af; 653ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 654ac35ff17SAlexander V. Chernikov } 655ac35ff17SAlexander V. Chernikov 656ac35ff17SAlexander V. Chernikov static void 657ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 65881d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 659ac35ff17SAlexander V. Chernikov { 660ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 661ac35ff17SAlexander V. Chernikov int error; 662ac35ff17SAlexander V. Chernikov 663ac35ff17SAlexander V. Chernikov type = 0; 664ac35ff17SAlexander V. Chernikov vtype = 0; 665ac35ff17SAlexander V. Chernikov 66681d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 66781d3153dSAlexander V. Chernikov 66881d3153dSAlexander V. Chernikov if (error == 0) { 66981d3153dSAlexander V. Chernikov /* Table found. */ 67081d3153dSAlexander V. Chernikov type = xi->type; 67181d3153dSAlexander V. Chernikov vtype = xi->vtype; 67281d3153dSAlexander V. Chernikov } else { 67381d3153dSAlexander V. Chernikov if (error != ESRCH) 67481d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 67581d3153dSAlexander V. Chernikov oh->ntlv.name); 676ac35ff17SAlexander V. Chernikov /* 67781d3153dSAlexander V. Chernikov * Table does not exist. 67881d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 67981d3153dSAlexander V. Chernikov * before failing. 680ac35ff17SAlexander V. Chernikov */ 681ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 682ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 683ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 684ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 685ac35ff17SAlexander V. Chernikov /* 68681d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 68781d3153dSAlexander V. Chernikov * This should be changed for MFC. 688ac35ff17SAlexander V. Chernikov */ 68981d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 69081d3153dSAlexander V. Chernikov } else { 69181d3153dSAlexander V. Chernikov /* Inknown key */ 69281d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 693ac35ff17SAlexander V. Chernikov "key type", oh->ntlv.name); 69481d3153dSAlexander V. Chernikov } 695ac35ff17SAlexander V. Chernikov } 696ac35ff17SAlexander V. Chernikov 697ac35ff17SAlexander V. Chernikov tentry_fill_key_type(key, tent, type); 698ac35ff17SAlexander V. Chernikov 699ac35ff17SAlexander V. Chernikov *ptype = type; 700ac35ff17SAlexander V. Chernikov *pvtype = vtype; 701ac35ff17SAlexander V. Chernikov } 702ac35ff17SAlexander V. Chernikov 703ac35ff17SAlexander V. Chernikov static void 704ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 705ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 706ac35ff17SAlexander V. Chernikov { 707ac35ff17SAlexander V. Chernikov int code; 708ac35ff17SAlexander V. Chernikov char *p; 709ac35ff17SAlexander V. Chernikov 710ac35ff17SAlexander V. Chernikov switch (vtype) { 711ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 712ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 713ac35ff17SAlexander V. Chernikov if (*p != '\0') 714ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 715ac35ff17SAlexander V. Chernikov break; 716ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 717ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 718ac35ff17SAlexander V. Chernikov break; 719ac35ff17SAlexander V. Chernikov /* Try hostname */ 720ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 721ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 722ac35ff17SAlexander V. Chernikov break; 723ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 724ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 725ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 726ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 727ac35ff17SAlexander V. Chernikov } else { 728ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 729ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 730ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 731ac35ff17SAlexander V. Chernikov } 732ac35ff17SAlexander V. Chernikov tent->value = code; 733ac35ff17SAlexander V. Chernikov break; 734ac35ff17SAlexander V. Chernikov default: 735ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 736ac35ff17SAlexander V. Chernikov } 737ac35ff17SAlexander V. Chernikov } 738f1220db8SAlexander V. Chernikov 739f1220db8SAlexander V. Chernikov /* 740f1220db8SAlexander V. Chernikov * Compare table names. 741f1220db8SAlexander V. Chernikov * Honor number comparison. 742f1220db8SAlexander V. Chernikov */ 743f1220db8SAlexander V. Chernikov static int 744f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 745f1220db8SAlexander V. Chernikov { 746f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 747f1220db8SAlexander V. Chernikov int la, lb; 748f1220db8SAlexander V. Chernikov 749f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 750f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 751f1220db8SAlexander V. Chernikov la = strlen(ia->tablename); 752f1220db8SAlexander V. Chernikov lb = strlen(ib->tablename); 753f1220db8SAlexander V. Chernikov 754f1220db8SAlexander V. Chernikov if (la > lb) 755f1220db8SAlexander V. Chernikov return (1); 756f1220db8SAlexander V. Chernikov else if (la < lb) 757f1220db8SAlexander V. Chernikov return (-01); 758f1220db8SAlexander V. Chernikov 759f1220db8SAlexander V. Chernikov return (strcmp(ia->tablename, ib->tablename)); 760f1220db8SAlexander V. Chernikov } 761f1220db8SAlexander V. Chernikov 762f1220db8SAlexander V. Chernikov /* 763f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 764f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 765f1220db8SAlexander V. Chernikov * Returns 0 on success. 766f1220db8SAlexander V. Chernikov */ 767f1220db8SAlexander V. Chernikov static int 768f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 769f1220db8SAlexander V. Chernikov { 770f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 771f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 772f1220db8SAlexander V. Chernikov size_t sz; 773f1220db8SAlexander V. Chernikov int i, error; 774f1220db8SAlexander V. Chernikov 775f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 776f1220db8SAlexander V. Chernikov sz = sizeof(req); 777f1220db8SAlexander V. Chernikov 778d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 779f1220db8SAlexander V. Chernikov return (errno); 780f1220db8SAlexander V. Chernikov 781f1220db8SAlexander V. Chernikov sz = req.size; 782f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 783f1220db8SAlexander V. Chernikov return (ENOMEM); 784f1220db8SAlexander V. Chernikov 785f1220db8SAlexander V. Chernikov olh->size = sz; 786d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 787f1220db8SAlexander V. Chernikov free(olh); 788f1220db8SAlexander V. Chernikov return (errno); 789f1220db8SAlexander V. Chernikov } 790f1220db8SAlexander V. Chernikov 791f1220db8SAlexander V. Chernikov if (sort != 0) 792f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 793f1220db8SAlexander V. Chernikov 794f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 795f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 796f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 797f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 798f1220db8SAlexander V. Chernikov } 799f1220db8SAlexander V. Chernikov 800f1220db8SAlexander V. Chernikov free(olh); 801f1220db8SAlexander V. Chernikov 802f1220db8SAlexander V. Chernikov return (0); 803f1220db8SAlexander V. Chernikov } 804f1220db8SAlexander V. Chernikov 805f1220db8SAlexander V. Chernikov /* 806f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 807d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 808d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 809f1220db8SAlexander V. Chernikov * 810f1220db8SAlexander V. Chernikov * Returns 0 on success. 811f1220db8SAlexander V. Chernikov */ 812f1220db8SAlexander V. Chernikov static int 813f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 814f1220db8SAlexander V. Chernikov { 815f1220db8SAlexander V. Chernikov size_t sz; 81681d3153dSAlexander V. Chernikov int error, c; 817f1220db8SAlexander V. Chernikov 81881d3153dSAlexander V. Chernikov sz = 0; 81981d3153dSAlexander V. Chernikov for (c = 0; c < 3; c++) { 820f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 82181d3153dSAlexander V. Chernikov if (sz < i->size) 822f1220db8SAlexander V. Chernikov sz = i->size; 823f1220db8SAlexander V. Chernikov 824d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 82581d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 826d3a4f924SAlexander V. Chernikov 82781d3153dSAlexander V. Chernikov if (error != ENOMEM) 828f1220db8SAlexander V. Chernikov return (errno); 82981d3153dSAlexander V. Chernikov } 830f1220db8SAlexander V. Chernikov 83181d3153dSAlexander V. Chernikov return (ENOMEM); 832f1220db8SAlexander V. Chernikov } 833f1220db8SAlexander V. Chernikov 834f1220db8SAlexander V. Chernikov /* 835f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 836f1220db8SAlexander V. Chernikov */ 837f1220db8SAlexander V. Chernikov static void 838f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 839f1220db8SAlexander V. Chernikov { 84081d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 84181d3153dSAlexander V. Chernikov uint32_t count; 842f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 843f1220db8SAlexander V. Chernikov 844f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 84581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 846f1220db8SAlexander V. Chernikov 847f1220db8SAlexander V. Chernikov if (need_header) 848f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 849f1220db8SAlexander V. Chernikov 850f1220db8SAlexander V. Chernikov count = i->count; 851f1220db8SAlexander V. Chernikov while (count > 0) { 85281d3153dSAlexander V. Chernikov table_show_entry(i, tent); 85381d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 85481d3153dSAlexander V. Chernikov count--; 85581d3153dSAlexander V. Chernikov } 85681d3153dSAlexander V. Chernikov } 85781d3153dSAlexander V. Chernikov 85881d3153dSAlexander V. Chernikov static void 85981d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 86081d3153dSAlexander V. Chernikov { 86181d3153dSAlexander V. Chernikov char tbuf[128]; 86281d3153dSAlexander V. Chernikov uint32_t tval; 86381d3153dSAlexander V. Chernikov 86481d3153dSAlexander V. Chernikov tval = tent->value; 86581d3153dSAlexander V. Chernikov 866f1220db8SAlexander V. Chernikov switch (i->type) { 867f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 868f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 86981d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 870f1220db8SAlexander V. Chernikov 871f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 872f1220db8SAlexander V. Chernikov tval = htonl(tval); 87381d3153dSAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, 874f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 875f1220db8SAlexander V. Chernikov } else 87681d3153dSAlexander V. Chernikov printf("%s/%u %u\n", tbuf, tent->masklen, tval); 877f1220db8SAlexander V. Chernikov break; 878f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 879f1220db8SAlexander V. Chernikov /* Interface names */ 880f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 881f1220db8SAlexander V. Chernikov tval = htonl(tval); 88281d3153dSAlexander V. Chernikov printf("%s %s\n", tent->k.iface, 883f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 884f1220db8SAlexander V. Chernikov } else 88581d3153dSAlexander V. Chernikov printf("%s %u\n", tent->k.iface, tval); 886f1220db8SAlexander V. Chernikov } 887f1220db8SAlexander V. Chernikov } 888f1220db8SAlexander V. Chernikov 8896c2997ffSAlexander V. Chernikov int 8906c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 8916c2997ffSAlexander V. Chernikov { 8926c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 8936c2997ffSAlexander V. Chernikov 8946c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 8956c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 8966c2997ffSAlexander V. Chernikov 8976c2997ffSAlexander V. Chernikov if (a->set < b->set) 8986c2997ffSAlexander V. Chernikov return (-1); 8996c2997ffSAlexander V. Chernikov else if (a->set > b->set) 9006c2997ffSAlexander V. Chernikov return (1); 9016c2997ffSAlexander V. Chernikov 9026c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 9036c2997ffSAlexander V. Chernikov return (-1); 9046c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 9056c2997ffSAlexander V. Chernikov return (1); 9066c2997ffSAlexander V. Chernikov 9076c2997ffSAlexander V. Chernikov return (0); 9086c2997ffSAlexander V. Chernikov } 909563b5ab1SAlexander V. Chernikov 910563b5ab1SAlexander V. Chernikov int 9116c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 912563b5ab1SAlexander V. Chernikov { 913563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 914563b5ab1SAlexander V. Chernikov uint16_t key; 915563b5ab1SAlexander V. Chernikov 916563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 917563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 918563b5ab1SAlexander V. Chernikov 919563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 920563b5ab1SAlexander V. Chernikov return (-1); 921563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 922563b5ab1SAlexander V. Chernikov return (1); 923563b5ab1SAlexander V. Chernikov 924563b5ab1SAlexander V. Chernikov return (0); 925563b5ab1SAlexander V. Chernikov } 926563b5ab1SAlexander V. Chernikov 927563b5ab1SAlexander V. Chernikov /* 928563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 929563b5ab1SAlexander V. Chernikov * Uses the following facts: 930563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 931563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 932563b5ab1SAlexander V. Chernikov * 933563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 934563b5ab1SAlexander V. Chernikov */ 935563b5ab1SAlexander V. Chernikov char * 936563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 937563b5ab1SAlexander V. Chernikov { 938563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 939563b5ab1SAlexander V. Chernikov 940563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 9416c2997ffSAlexander V. Chernikov compare_kntlv); 942563b5ab1SAlexander V. Chernikov 943563b5ab1SAlexander V. Chernikov if (ntlv != 0) 944563b5ab1SAlexander V. Chernikov return (ntlv->name); 945563b5ab1SAlexander V. Chernikov 946563b5ab1SAlexander V. Chernikov return (NULL); 947563b5ab1SAlexander V. Chernikov } 948563b5ab1SAlexander V. Chernikov 9496c2997ffSAlexander V. Chernikov void 9506c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 9516c2997ffSAlexander V. Chernikov { 9526c2997ffSAlexander V. Chernikov 9536c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 9546c2997ffSAlexander V. Chernikov } 9556c2997ffSAlexander V. Chernikov 9566c2997ffSAlexander V. Chernikov int 9576c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 9586c2997ffSAlexander V. Chernikov { 9596c2997ffSAlexander V. Chernikov int c, i, l; 9606c2997ffSAlexander V. Chernikov 9616c2997ffSAlexander V. Chernikov /* 9626c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 9636c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 964ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 9656c2997ffSAlexander V. Chernikov */ 9666c2997ffSAlexander V. Chernikov l = strlen(tablename); 9676c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 9686c2997ffSAlexander V. Chernikov return (EINVAL); 9696c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 9706c2997ffSAlexander V. Chernikov c = tablename[i]; 9716c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 9726c2997ffSAlexander V. Chernikov c == '-' || c == '.') 9736c2997ffSAlexander V. Chernikov continue; 9746c2997ffSAlexander V. Chernikov return (EINVAL); 9756c2997ffSAlexander V. Chernikov } 9766c2997ffSAlexander V. Chernikov 977ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 978ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 979ac35ff17SAlexander V. Chernikov return (EINVAL); 980ac35ff17SAlexander V. Chernikov 9816c2997ffSAlexander V. Chernikov return (0); 9826c2997ffSAlexander V. Chernikov } 9836c2997ffSAlexander V. Chernikov 984