1f1220db8SAlexander V. Chernikov /* 2f1220db8SAlexander V. Chernikov * Copyright (c) 2002-2003 Luigi Rizzo 3f1220db8SAlexander V. Chernikov * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4f1220db8SAlexander V. Chernikov * Copyright (c) 1994 Ugen J.S.Antsilevich 5f1220db8SAlexander V. Chernikov * 6f1220db8SAlexander V. Chernikov * Idea and grammar partially left from: 7f1220db8SAlexander V. Chernikov * Copyright (c) 1993 Daniel Boulet 8f1220db8SAlexander V. Chernikov * 9f1220db8SAlexander V. Chernikov * Redistribution and use in source forms, with and without modification, 10f1220db8SAlexander V. Chernikov * are permitted provided that this entire comment appears intact. 11f1220db8SAlexander V. Chernikov * 12f1220db8SAlexander V. Chernikov * Redistribution in binary form may occur without any restrictions. 13f1220db8SAlexander V. Chernikov * Obviously, it would be nice if you gave credit where credit is due 14f1220db8SAlexander V. Chernikov * but requiring it would be too onerous. 15f1220db8SAlexander V. Chernikov * 16f1220db8SAlexander V. Chernikov * This software is provided ``AS IS'' without any warranties of any kind. 17f1220db8SAlexander V. Chernikov * 18f1220db8SAlexander V. Chernikov * in-kernel tables support 19f1220db8SAlexander V. Chernikov * 20f1220db8SAlexander V. Chernikov * $FreeBSD: projects/ipfw/sbin/ipfw/ipfw2.c 267467 2014-06-14 10:58:39Z melifaro $ 21f1220db8SAlexander V. Chernikov */ 22f1220db8SAlexander V. Chernikov 23f1220db8SAlexander V. Chernikov 24f1220db8SAlexander V. Chernikov #include <sys/types.h> 25f1220db8SAlexander V. Chernikov #include <sys/param.h> 26f1220db8SAlexander V. Chernikov #include <sys/socket.h> 27f1220db8SAlexander V. Chernikov #include <sys/sysctl.h> 28f1220db8SAlexander V. Chernikov 29f1220db8SAlexander V. Chernikov #include <ctype.h> 30f1220db8SAlexander V. Chernikov #include <err.h> 31f1220db8SAlexander V. Chernikov #include <errno.h> 32f1220db8SAlexander V. Chernikov #include <netdb.h> 33f1220db8SAlexander V. Chernikov #include <stddef.h> /* offsetof */ 34f1220db8SAlexander V. Chernikov #include <stdio.h> 35f1220db8SAlexander V. Chernikov #include <stdlib.h> 36f1220db8SAlexander V. Chernikov #include <string.h> 37f1220db8SAlexander V. Chernikov #include <sysexits.h> 38f1220db8SAlexander V. Chernikov 39f1220db8SAlexander V. Chernikov #define IPFW_INTERNAL /* Access to protected structures in ip_fw.h. */ 40f1220db8SAlexander V. Chernikov 41f1220db8SAlexander V. Chernikov #include <net/if.h> 42f1220db8SAlexander V. Chernikov #include <net/if_dl.h> 43f1220db8SAlexander V. Chernikov #include <net/route.h> /* def. of struct route */ 44f1220db8SAlexander V. Chernikov #include <netinet/in.h> 45f1220db8SAlexander V. Chernikov #include <netinet/ip_fw.h> 46f1220db8SAlexander V. Chernikov #include <arpa/inet.h> 47f1220db8SAlexander V. Chernikov #include <alias.h> 48f1220db8SAlexander V. Chernikov 49f1220db8SAlexander V. Chernikov #include "ipfw2.h" 50f1220db8SAlexander V. Chernikov 51f1220db8SAlexander V. Chernikov static void table_list(ipfw_xtable_info *i, int need_header); 52ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 53ac35ff17SAlexander V. Chernikov int add, int update); 54ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh); 55ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh); 56ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 57ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 5881d3153dSAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 59ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 60f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 61ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, 62ac35ff17SAlexander V. Chernikov uint16_t uidx); 63f1220db8SAlexander V. Chernikov 64f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 65f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 66f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh); 67f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 6881d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 69f1220db8SAlexander V. Chernikov 70ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 7181d3153dSAlexander V. Chernikov char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); 72ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 73ac35ff17SAlexander V. Chernikov char *arg, uint8_t type, uint8_t vtype); 74ac35ff17SAlexander V. Chernikov 75f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 76f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 77f1220db8SAlexander V. Chernikov 78f1220db8SAlexander V. Chernikov #ifndef s6_addr32 79f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 80f1220db8SAlexander V. Chernikov #endif 81f1220db8SAlexander V. Chernikov 82ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 83ac35ff17SAlexander V. Chernikov { "cidr", IPFW_TABLE_CIDR }, 84ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 85b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 86*914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 87ac35ff17SAlexander V. Chernikov { NULL, 0 } 88ac35ff17SAlexander V. Chernikov }; 89ac35ff17SAlexander V. Chernikov 90ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 91ac35ff17SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 92ac35ff17SAlexander V. Chernikov { "ip", IPFW_VTYPE_IP }, 93ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 94ac35ff17SAlexander V. Chernikov { NULL, 0 } 95ac35ff17SAlexander V. Chernikov }; 96ac35ff17SAlexander V. Chernikov 97ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 98ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 99ac35ff17SAlexander V. Chernikov { "create", TOK_CREATE }, 100ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 101ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 102ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 103ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 104ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 10581d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 106ac35ff17SAlexander V. Chernikov { NULL, 0 } 107ac35ff17SAlexander V. Chernikov }; 108ac35ff17SAlexander V. Chernikov 109f1220db8SAlexander V. Chernikov static int 110f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 111f1220db8SAlexander V. Chernikov { 112f1220db8SAlexander V. Chernikov struct hostent *he; 113f1220db8SAlexander V. Chernikov 114f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 115f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 116f1220db8SAlexander V. Chernikov return(-1); 117f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 118f1220db8SAlexander V. Chernikov } 119f1220db8SAlexander V. Chernikov return(0); 120f1220db8SAlexander V. Chernikov } 121f1220db8SAlexander V. Chernikov 122f1220db8SAlexander V. Chernikov /* 123f1220db8SAlexander V. Chernikov * This one handles all table-related commands 124ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 125ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 126ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 127ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 128ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 129ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 130ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 131f1220db8SAlexander V. Chernikov */ 132f1220db8SAlexander V. Chernikov void 133f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 134f1220db8SAlexander V. Chernikov { 135ac35ff17SAlexander V. Chernikov int do_add, is_all; 136ac35ff17SAlexander V. Chernikov int error, tcmd; 137ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 138ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 139f1220db8SAlexander V. Chernikov char *tablename; 140ac35ff17SAlexander V. Chernikov uint32_t set; 141f1220db8SAlexander V. Chernikov 142ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 143ac35ff17SAlexander V. Chernikov is_all = 0; 144ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 145ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 146ac35ff17SAlexander V. Chernikov else 147ac35ff17SAlexander V. Chernikov set = 0; 148f1220db8SAlexander V. Chernikov 149f1220db8SAlexander V. Chernikov ac--; av++; 1509d099b4fSAlexander V. Chernikov NEED1("table needs name"); 151f1220db8SAlexander V. Chernikov tablename = *av; 152f1220db8SAlexander V. Chernikov 153ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 154ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 155ac35ff17SAlexander V. Chernikov oh.idx = 1; 156ac35ff17SAlexander V. Chernikov } else { 157ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 158ac35ff17SAlexander V. Chernikov is_all = 1; 159ac35ff17SAlexander V. Chernikov else 160ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 161ac35ff17SAlexander V. Chernikov } 162ac35ff17SAlexander V. Chernikov ac--; av++; 1639d099b4fSAlexander V. Chernikov NEED1("table needs command"); 164ac35ff17SAlexander V. Chernikov 165ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 166ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 167ac35ff17SAlexander V. Chernikov 168ac35ff17SAlexander V. Chernikov switch (tcmd) { 169ac35ff17SAlexander V. Chernikov case TOK_LIST: 170ac35ff17SAlexander V. Chernikov case TOK_INFO: 171ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 172ac35ff17SAlexander V. Chernikov break; 173ac35ff17SAlexander V. Chernikov default: 174ac35ff17SAlexander V. Chernikov if (is_all != 0) 175ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 176ac35ff17SAlexander V. Chernikov } 177ac35ff17SAlexander V. Chernikov 178ac35ff17SAlexander V. Chernikov switch (tcmd) { 179ac35ff17SAlexander V. Chernikov case TOK_ADD: 180ac35ff17SAlexander V. Chernikov case TOK_DEL: 181f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 182f1220db8SAlexander V. Chernikov ac--; av++; 183ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 184ac35ff17SAlexander V. Chernikov break; 185ac35ff17SAlexander V. Chernikov case TOK_CREATE: 186f1220db8SAlexander V. Chernikov ac--; av++; 187ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 188ac35ff17SAlexander V. Chernikov break; 189ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 190ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 191ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 192ac35ff17SAlexander V. Chernikov break; 193ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 194f1220db8SAlexander V. Chernikov if (is_all == 0) { 195ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 196f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 197f1220db8SAlexander V. Chernikov tablename); 198f1220db8SAlexander V. Chernikov } else { 199ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 200f1220db8SAlexander V. Chernikov if (error != 0) 201f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 202f1220db8SAlexander V. Chernikov } 203ac35ff17SAlexander V. Chernikov break; 204ac35ff17SAlexander V. Chernikov case TOK_INFO: 205f1220db8SAlexander V. Chernikov if (is_all == 0) { 206ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 207f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 208f1220db8SAlexander V. Chernikov table_show_info(&i, NULL); 209f1220db8SAlexander V. Chernikov } else { 210f1220db8SAlexander V. Chernikov error = tables_foreach(table_show_info, NULL, 1); 211f1220db8SAlexander V. Chernikov if (error != 0) 212f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 213f1220db8SAlexander V. Chernikov } 214ac35ff17SAlexander V. Chernikov break; 215ac35ff17SAlexander V. Chernikov case TOK_LIST: 216ac35ff17SAlexander V. Chernikov if (is_all == 0) { 217ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 218ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 219ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 220ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 221f1220db8SAlexander V. Chernikov } else { 222ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 223ac35ff17SAlexander V. Chernikov if (error != 0) 224ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 225f1220db8SAlexander V. Chernikov } 226ac35ff17SAlexander V. Chernikov break; 22781d3153dSAlexander V. Chernikov case TOK_LOOKUP: 22881d3153dSAlexander V. Chernikov ac--; av++; 22981d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 23081d3153dSAlexander V. Chernikov break; 231f1220db8SAlexander V. Chernikov } 232f1220db8SAlexander V. Chernikov } 233f1220db8SAlexander V. Chernikov 234f1220db8SAlexander V. Chernikov static void 235ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 236f1220db8SAlexander V. Chernikov { 237f1220db8SAlexander V. Chernikov 238563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 239f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 240f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 241ac35ff17SAlexander V. Chernikov ntlv->set = set; 242f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 243f1220db8SAlexander V. Chernikov } 244f1220db8SAlexander V. Chernikov 245f1220db8SAlexander V. Chernikov static void 246f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 247f1220db8SAlexander V. Chernikov { 248f1220db8SAlexander V. Chernikov 249f1220db8SAlexander V. Chernikov oh->idx = 1; 25081d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 251ac35ff17SAlexander V. Chernikov } 252ac35ff17SAlexander V. Chernikov 253ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 254ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE}, 255ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 256ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 257ac35ff17SAlexander V. Chernikov { NULL, 0 } 258ac35ff17SAlexander V. Chernikov }; 259ac35ff17SAlexander V. Chernikov 260*914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 261*914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 262*914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 263*914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 264*914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 265*914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 266*914bffb6SAlexander V. Chernikov { NULL, 0 } 267*914bffb6SAlexander V. Chernikov }; 268*914bffb6SAlexander V. Chernikov 269*914bffb6SAlexander V. Chernikov int 270*914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 271*914bffb6SAlexander V. Chernikov { 272*914bffb6SAlexander V. Chernikov uint8_t fset, fclear; 273*914bffb6SAlexander V. Chernikov 274*914bffb6SAlexander V. Chernikov /* Parse type options */ 275*914bffb6SAlexander V. Chernikov switch(ttype) { 276*914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 277*914bffb6SAlexander V. Chernikov fset = fclear = 0; 278*914bffb6SAlexander V. Chernikov fill_flags(flowtypecmds, p, &fset, 279*914bffb6SAlexander V. Chernikov &fclear); 280*914bffb6SAlexander V. Chernikov *tflags = fset; 281*914bffb6SAlexander V. Chernikov break; 282*914bffb6SAlexander V. Chernikov default: 283*914bffb6SAlexander V. Chernikov return (EX_USAGE); 284*914bffb6SAlexander V. Chernikov } 285*914bffb6SAlexander V. Chernikov 286*914bffb6SAlexander V. Chernikov return (0); 287*914bffb6SAlexander V. Chernikov } 288*914bffb6SAlexander V. Chernikov 289*914bffb6SAlexander V. Chernikov void 290*914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 291*914bffb6SAlexander V. Chernikov { 292*914bffb6SAlexander V. Chernikov const char *tname; 293*914bffb6SAlexander V. Chernikov int l; 294*914bffb6SAlexander V. Chernikov 295*914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 296*914bffb6SAlexander V. Chernikov tname = "unknown"; 297*914bffb6SAlexander V. Chernikov 298*914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 299*914bffb6SAlexander V. Chernikov tbuf += l; 300*914bffb6SAlexander V. Chernikov size -= l; 301*914bffb6SAlexander V. Chernikov 302*914bffb6SAlexander V. Chernikov switch(type) { 303*914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 304*914bffb6SAlexander V. Chernikov if (tflags != 0) { 305*914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 306*914bffb6SAlexander V. Chernikov l--; 307*914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 308*914bffb6SAlexander V. Chernikov } 309*914bffb6SAlexander V. Chernikov break; 310*914bffb6SAlexander V. Chernikov } 311*914bffb6SAlexander V. Chernikov } 312*914bffb6SAlexander V. Chernikov 313ac35ff17SAlexander V. Chernikov /* 314ac35ff17SAlexander V. Chernikov * Creates new table 315ac35ff17SAlexander V. Chernikov * 316ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 317ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 318ac35ff17SAlexander V. Chernikov * [ algo algoname ] 319ac35ff17SAlexander V. Chernikov * 320ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 321ac35ff17SAlexander V. Chernikov */ 322ac35ff17SAlexander V. Chernikov static void 323ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 324ac35ff17SAlexander V. Chernikov { 325ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 326ac35ff17SAlexander V. Chernikov int error, tcmd, val; 327ac35ff17SAlexander V. Chernikov size_t sz; 328*914bffb6SAlexander V. Chernikov char *p; 329ac35ff17SAlexander V. Chernikov char tbuf[128]; 330ac35ff17SAlexander V. Chernikov 331ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 332ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 333ac35ff17SAlexander V. Chernikov 334ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 335ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 336ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 337ac35ff17SAlexander V. Chernikov 338ac35ff17SAlexander V. Chernikov while (ac > 0) { 339ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 340ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 341ac35ff17SAlexander V. Chernikov ac--; av++; 342ac35ff17SAlexander V. Chernikov 343ac35ff17SAlexander V. Chernikov switch (tcmd) { 344ac35ff17SAlexander V. Chernikov case TOK_TYPE: 345ac35ff17SAlexander V. Chernikov NEED1("table type required"); 346*914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 347*914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 348*914bffb6SAlexander V. Chernikov *p++ = '\0'; 349ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 350*914bffb6SAlexander V. Chernikov if (val == -1) { 351*914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 352*914bffb6SAlexander V. Chernikov ", "); 353*914bffb6SAlexander V. Chernikov errx(EX_USAGE, 354*914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 355ac35ff17SAlexander V. Chernikov *av, tbuf); 356*914bffb6SAlexander V. Chernikov } 357*914bffb6SAlexander V. Chernikov xi.type = val; 358*914bffb6SAlexander V. Chernikov if (p != NULL) { 359*914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 360*914bffb6SAlexander V. Chernikov if (error != 0) 361*914bffb6SAlexander V. Chernikov errx(EX_USAGE, 362*914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 363*914bffb6SAlexander V. Chernikov } 364*914bffb6SAlexander V. Chernikov ac--; av++; 365ac35ff17SAlexander V. Chernikov break; 366ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 367ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 368ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 369ac35ff17SAlexander V. Chernikov if (val != -1) { 370ac35ff17SAlexander V. Chernikov xi.vtype = val; 371ac35ff17SAlexander V. Chernikov ac--; av++; 372ac35ff17SAlexander V. Chernikov break; 373ac35ff17SAlexander V. Chernikov } 374ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 375ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 376ac35ff17SAlexander V. Chernikov *av, tbuf); 377ac35ff17SAlexander V. Chernikov break; 378ac35ff17SAlexander V. Chernikov case TOK_ALGO: 379ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 380ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 381ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 382ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 383ac35ff17SAlexander V. Chernikov ac--; av++; 384ac35ff17SAlexander V. Chernikov break; 385ac35ff17SAlexander V. Chernikov } 386ac35ff17SAlexander V. Chernikov } 387ac35ff17SAlexander V. Chernikov 388ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 389ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 390f1220db8SAlexander V. Chernikov } 391f1220db8SAlexander V. Chernikov 392f1220db8SAlexander V. Chernikov /* 393ac35ff17SAlexander V. Chernikov * Creates new table 394ac35ff17SAlexander V. Chernikov * 395ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 396ac35ff17SAlexander V. Chernikov * 397f1220db8SAlexander V. Chernikov * Returns 0 on success. 398f1220db8SAlexander V. Chernikov */ 399f1220db8SAlexander V. Chernikov static int 400ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 401f1220db8SAlexander V. Chernikov { 402ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 403ac35ff17SAlexander V. Chernikov int error; 404f1220db8SAlexander V. Chernikov 405ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 406ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 407ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 408ac35ff17SAlexander V. Chernikov 409ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 410ac35ff17SAlexander V. Chernikov 411ac35ff17SAlexander V. Chernikov return (error); 412ac35ff17SAlexander V. Chernikov } 413ac35ff17SAlexander V. Chernikov 414ac35ff17SAlexander V. Chernikov /* 415ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 416ac35ff17SAlexander V. Chernikov * Returns 0 on success. 417ac35ff17SAlexander V. Chernikov */ 418ac35ff17SAlexander V. Chernikov static int 419ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 420ac35ff17SAlexander V. Chernikov { 421ac35ff17SAlexander V. Chernikov 422ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 423f1220db8SAlexander V. Chernikov return (-1); 424f1220db8SAlexander V. Chernikov 425f1220db8SAlexander V. Chernikov return (0); 426f1220db8SAlexander V. Chernikov } 427f1220db8SAlexander V. Chernikov 428f1220db8SAlexander V. Chernikov /* 429ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 430f1220db8SAlexander V. Chernikov * Returns 0 on success. 431f1220db8SAlexander V. Chernikov */ 432f1220db8SAlexander V. Chernikov static int 433ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 434f1220db8SAlexander V. Chernikov { 435f1220db8SAlexander V. Chernikov 436ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 437f1220db8SAlexander V. Chernikov return (-1); 438f1220db8SAlexander V. Chernikov 439f1220db8SAlexander V. Chernikov return (0); 440f1220db8SAlexander V. Chernikov } 441f1220db8SAlexander V. Chernikov 442f1220db8SAlexander V. Chernikov /* 443ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 444f1220db8SAlexander V. Chernikov * it inside @i. 445f1220db8SAlexander V. Chernikov * Returns 0 on success. 446f1220db8SAlexander V. Chernikov */ 447f1220db8SAlexander V. Chernikov static int 448ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 449f1220db8SAlexander V. Chernikov { 450f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 451ac35ff17SAlexander V. Chernikov int error; 452f1220db8SAlexander V. Chernikov size_t sz; 453f1220db8SAlexander V. Chernikov 454f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 455f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 456ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 457f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 458f1220db8SAlexander V. Chernikov 459ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 460ac35ff17SAlexander V. Chernikov return (error); 461f1220db8SAlexander V. Chernikov 462f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 463ac35ff17SAlexander V. Chernikov return (EINVAL); 464f1220db8SAlexander V. Chernikov 465f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 466f1220db8SAlexander V. Chernikov 467f1220db8SAlexander V. Chernikov return (0); 468f1220db8SAlexander V. Chernikov } 469f1220db8SAlexander V. Chernikov 470f1220db8SAlexander V. Chernikov /* 471f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 472f1220db8SAlexander V. Chernikov */ 473f1220db8SAlexander V. Chernikov static int 474f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 475f1220db8SAlexander V. Chernikov { 476*914bffb6SAlexander V. Chernikov const char *vtype; 477*914bffb6SAlexander V. Chernikov char ttype[64]; 478f1220db8SAlexander V. Chernikov 479*914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 480ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 481ac35ff17SAlexander V. Chernikov vtype = "unknown"; 482ac35ff17SAlexander V. Chernikov 483*914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 484*914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 4859d099b4fSAlexander V. Chernikov printf(" valtype: %s, references: %u\n", vtype, i->refcnt); 4869d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 487f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 488f1220db8SAlexander V. Chernikov 489f1220db8SAlexander V. Chernikov return (0); 490f1220db8SAlexander V. Chernikov } 491f1220db8SAlexander V. Chernikov 492f1220db8SAlexander V. Chernikov 493f1220db8SAlexander V. Chernikov /* 494f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 495f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 496f1220db8SAlexander V. Chernikov */ 497f1220db8SAlexander V. Chernikov 498f1220db8SAlexander V. Chernikov static int 499f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 500f1220db8SAlexander V. Chernikov { 501f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 50281d3153dSAlexander V. Chernikov int error; 503f1220db8SAlexander V. Chernikov 504ac35ff17SAlexander V. Chernikov if ((oh = calloc(1, i->size)) == NULL) 505f1220db8SAlexander V. Chernikov return (ENOMEM); 506f1220db8SAlexander V. Chernikov 50781d3153dSAlexander V. Chernikov if ((error = table_get_list(i, oh)) != 0) { 50881d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 50981d3153dSAlexander V. Chernikov return (error); 51081d3153dSAlexander V. Chernikov } 51181d3153dSAlexander V. Chernikov 512f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 513f1220db8SAlexander V. Chernikov 514f1220db8SAlexander V. Chernikov free(oh); 515f1220db8SAlexander V. Chernikov return (0); 516f1220db8SAlexander V. Chernikov } 517f1220db8SAlexander V. Chernikov 518f1220db8SAlexander V. Chernikov static int 519f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 520f1220db8SAlexander V. Chernikov { 521ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 522f1220db8SAlexander V. Chernikov 523ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 524ac35ff17SAlexander V. Chernikov 525ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 526ac35ff17SAlexander V. Chernikov 527ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 528f1220db8SAlexander V. Chernikov } 529f1220db8SAlexander V. Chernikov 530ac35ff17SAlexander V. Chernikov static int 531ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 532ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 533ac35ff17SAlexander V. Chernikov { 534db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 535db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 536ac35ff17SAlexander V. Chernikov int error; 537ac35ff17SAlexander V. Chernikov 538ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 539ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 540ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 541ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 542ac35ff17SAlexander V. Chernikov 543db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 544db785d31SAlexander V. Chernikov ctlv->count = 1; 545db785d31SAlexander V. Chernikov ctlv->head.length = sizeof(*ctlv) + sizeof(*tent); 546db785d31SAlexander V. Chernikov 547db785d31SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent)); 548db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 549ac35ff17SAlexander V. Chernikov if (update != 0) 55081d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 551ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 552ac35ff17SAlexander V. Chernikov 553ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 554ac35ff17SAlexander V. Chernikov 555ac35ff17SAlexander V. Chernikov return (error); 556ac35ff17SAlexander V. Chernikov } 557ac35ff17SAlexander V. Chernikov 558ac35ff17SAlexander V. Chernikov static void 559ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 560ac35ff17SAlexander V. Chernikov { 561ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 56281d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 563ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 564ac35ff17SAlexander V. Chernikov int cmd; 565ac35ff17SAlexander V. Chernikov char *texterr; 566ac35ff17SAlexander V. Chernikov 567ac35ff17SAlexander V. Chernikov if (ac == 0) 568ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 569ac35ff17SAlexander V. Chernikov 570ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 571ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 572ac35ff17SAlexander V. Chernikov tent.idx = 1; 573ac35ff17SAlexander V. Chernikov 57481d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 575db785d31SAlexander V. Chernikov 576db785d31SAlexander V. Chernikov /* 577db785d31SAlexander V. Chernikov * compability layer: auto-create table if not exists 578db785d31SAlexander V. Chernikov */ 579db785d31SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 580db785d31SAlexander V. Chernikov xi.type = type; 581db785d31SAlexander V. Chernikov xi.vtype = vtype; 582db785d31SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); 583db785d31SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info non-existent " 584db785d31SAlexander V. Chernikov "table %s. (auto-created)\n", xi.tablename); 585db785d31SAlexander V. Chernikov table_do_create(oh, &xi); 586db785d31SAlexander V. Chernikov } 587db785d31SAlexander V. Chernikov 588ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 589ac35ff17SAlexander V. Chernikov ac--; av++; 590ac35ff17SAlexander V. Chernikov 591ac35ff17SAlexander V. Chernikov if (add != 0) { 592ac35ff17SAlexander V. Chernikov if (ac > 0) 593ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 594ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 595ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XADD)"; 596ac35ff17SAlexander V. Chernikov } else { 597ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 598ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XDEL)"; 599ac35ff17SAlexander V. Chernikov } 600ac35ff17SAlexander V. Chernikov 601ac35ff17SAlexander V. Chernikov if (table_do_modify_record(cmd, oh, &tent, update) != 0) 602ac35ff17SAlexander V. Chernikov err(EX_OSERR, "%s", texterr); 603ac35ff17SAlexander V. Chernikov } 604ac35ff17SAlexander V. Chernikov 60581d3153dSAlexander V. Chernikov static int 60681d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 60781d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 60881d3153dSAlexander V. Chernikov { 60981d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 61081d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 61181d3153dSAlexander V. Chernikov uint8_t type, vtype; 61281d3153dSAlexander V. Chernikov int error; 61381d3153dSAlexander V. Chernikov size_t sz; 61481d3153dSAlexander V. Chernikov 61581d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 61681d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 61781d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 61881d3153dSAlexander V. Chernikov 61981d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 62081d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 62181d3153dSAlexander V. Chernikov tent->idx = 1; 62281d3153dSAlexander V. Chernikov 62381d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 62481d3153dSAlexander V. Chernikov oh->ntlv.type = type; 62581d3153dSAlexander V. Chernikov 62681d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 62781d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 62881d3153dSAlexander V. Chernikov return (error); 62981d3153dSAlexander V. Chernikov 63081d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 63181d3153dSAlexander V. Chernikov return (EINVAL); 63281d3153dSAlexander V. Chernikov 63381d3153dSAlexander V. Chernikov *xtent = *tent; 63481d3153dSAlexander V. Chernikov 63581d3153dSAlexander V. Chernikov return (0); 63681d3153dSAlexander V. Chernikov } 63781d3153dSAlexander V. Chernikov 63881d3153dSAlexander V. Chernikov static void 63981d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 64081d3153dSAlexander V. Chernikov { 64181d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 64281d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 643*914bffb6SAlexander V. Chernikov char key[64]; 64481d3153dSAlexander V. Chernikov int error; 64581d3153dSAlexander V. Chernikov 64681d3153dSAlexander V. Chernikov if (ac == 0) 64781d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 64881d3153dSAlexander V. Chernikov 649*914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 650*914bffb6SAlexander V. Chernikov 651*914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 65281d3153dSAlexander V. Chernikov 65381d3153dSAlexander V. Chernikov switch (error) { 65481d3153dSAlexander V. Chernikov case 0: 65581d3153dSAlexander V. Chernikov break; 65681d3153dSAlexander V. Chernikov case ESRCH: 65781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 65881d3153dSAlexander V. Chernikov case ENOENT: 65981d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 66081d3153dSAlexander V. Chernikov case ENOTSUP: 66181d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 66281d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 66381d3153dSAlexander V. Chernikov default: 66481d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 66581d3153dSAlexander V. Chernikov } 66681d3153dSAlexander V. Chernikov 66781d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 66881d3153dSAlexander V. Chernikov } 669ac35ff17SAlexander V. Chernikov 670ac35ff17SAlexander V. Chernikov static void 671*914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 672*914bffb6SAlexander V. Chernikov uint8_t tflags) 673ac35ff17SAlexander V. Chernikov { 674*914bffb6SAlexander V. Chernikov char *p, *pp; 675ac35ff17SAlexander V. Chernikov int mask, af; 676*914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 677*914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 678ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 679*914bffb6SAlexander V. Chernikov uint16_t port; 680*914bffb6SAlexander V. Chernikov struct protoent *pent; 681*914bffb6SAlexander V. Chernikov struct servent *sent; 682ac35ff17SAlexander V. Chernikov int masklen; 683ac35ff17SAlexander V. Chernikov 684ac35ff17SAlexander V. Chernikov masklen = 0; 685ac35ff17SAlexander V. Chernikov af = 0; 686ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 687ac35ff17SAlexander V. Chernikov 688ac35ff17SAlexander V. Chernikov switch (type) { 689ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 690ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 691ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 692ac35ff17SAlexander V. Chernikov *p = '\0'; 693ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 694ac35ff17SAlexander V. Chernikov } 695ac35ff17SAlexander V. Chernikov 696ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 697ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 698ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 699ac35ff17SAlexander V. Chernikov p + 1); 700ac35ff17SAlexander V. Chernikov 701ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 702ac35ff17SAlexander V. Chernikov af = AF_INET; 703ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 704ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 705ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 706ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 707ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 708ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 709ac35ff17SAlexander V. Chernikov p + 1); 710ac35ff17SAlexander V. Chernikov 711ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 712ac35ff17SAlexander V. Chernikov af = AF_INET6; 713ac35ff17SAlexander V. Chernikov } else { 714ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 715ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 716ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 717ac35ff17SAlexander V. Chernikov 718ac35ff17SAlexander V. Chernikov masklen = 32; 719ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 720ac35ff17SAlexander V. Chernikov af = AF_INET; 721ac35ff17SAlexander V. Chernikov } 722ac35ff17SAlexander V. Chernikov break; 723ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 724ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 725ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 726ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 727ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 728ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 729ac35ff17SAlexander V. Chernikov break; 730b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 731ac35ff17SAlexander V. Chernikov /* Port or any other key */ 732ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 733ac35ff17SAlexander V. Chernikov if (*p != '\0') 734ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 735ac35ff17SAlexander V. Chernikov 736ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 737ac35ff17SAlexander V. Chernikov *pkey = key; 738ac35ff17SAlexander V. Chernikov masklen = 32; 739ac35ff17SAlexander V. Chernikov break; 740*914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 741*914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 742*914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 743*914bffb6SAlexander V. Chernikov af = 0; 744*914bffb6SAlexander V. Chernikov 745*914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 746*914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 747*914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 748*914bffb6SAlexander V. Chernikov *p++ = '\0'; 749*914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 750*914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 751*914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 752*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 753*914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 754*914bffb6SAlexander V. Chernikov af = AF_INET; 755*914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 756*914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 757*914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 758*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 759*914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 760*914bffb6SAlexander V. Chernikov af = AF_INET6; 761*914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 762*914bffb6SAlexander V. Chernikov } 763*914bffb6SAlexander V. Chernikov 764*914bffb6SAlexander V. Chernikov arg = p; 765*914bffb6SAlexander V. Chernikov } 766*914bffb6SAlexander V. Chernikov 767*914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 768*914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 769*914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 770*914bffb6SAlexander V. Chernikov *p++ = '\0'; 771*914bffb6SAlexander V. Chernikov 772*914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 773*914bffb6SAlexander V. Chernikov if (*pp != '\0') { 774*914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 775*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 776*914bffb6SAlexander V. Chernikov arg); 777*914bffb6SAlexander V. Chernikov else 778*914bffb6SAlexander V. Chernikov key = pent->p_proto; 779*914bffb6SAlexander V. Chernikov } 780*914bffb6SAlexander V. Chernikov 781*914bffb6SAlexander V. Chernikov if (key > 255) 782*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 783*914bffb6SAlexander V. Chernikov 784*914bffb6SAlexander V. Chernikov tfe->proto = key; 785*914bffb6SAlexander V. Chernikov 786*914bffb6SAlexander V. Chernikov arg = p; 787*914bffb6SAlexander V. Chernikov } 788*914bffb6SAlexander V. Chernikov 789*914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 790*914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 791*914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 792*914bffb6SAlexander V. Chernikov *p++ = '\0'; 793*914bffb6SAlexander V. Chernikov 794*914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 795*914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 796*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 797*914bffb6SAlexander V. Chernikov arg); 798*914bffb6SAlexander V. Chernikov else 799*914bffb6SAlexander V. Chernikov key = sent->s_port; 800*914bffb6SAlexander V. Chernikov } 801*914bffb6SAlexander V. Chernikov 802*914bffb6SAlexander V. Chernikov tfe->sport = port; 803*914bffb6SAlexander V. Chernikov 804*914bffb6SAlexander V. Chernikov arg = p; 805*914bffb6SAlexander V. Chernikov } 806*914bffb6SAlexander V. Chernikov 807*914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 808*914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 809*914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 810*914bffb6SAlexander V. Chernikov *p++ = '\0'; 811*914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 812*914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 813*914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 814*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 815*914bffb6SAlexander V. Chernikov "Inconsistent address family"); 816*914bffb6SAlexander V. Chernikov af = AF_INET; 817*914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 818*914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 819*914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 820*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 821*914bffb6SAlexander V. Chernikov "Inconsistent address family"); 822*914bffb6SAlexander V. Chernikov af = AF_INET6; 823*914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 824*914bffb6SAlexander V. Chernikov } 825*914bffb6SAlexander V. Chernikov 826*914bffb6SAlexander V. Chernikov arg = p; 827*914bffb6SAlexander V. Chernikov } 828*914bffb6SAlexander V. Chernikov 829*914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 830*914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 831*914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 832*914bffb6SAlexander V. Chernikov *p++ = '\0'; 833*914bffb6SAlexander V. Chernikov 834*914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 835*914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 836*914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 837*914bffb6SAlexander V. Chernikov arg); 838*914bffb6SAlexander V. Chernikov else 839*914bffb6SAlexander V. Chernikov key = sent->s_port; 840*914bffb6SAlexander V. Chernikov } 841*914bffb6SAlexander V. Chernikov 842*914bffb6SAlexander V. Chernikov tfe->dport = port; 843*914bffb6SAlexander V. Chernikov 844*914bffb6SAlexander V. Chernikov arg = p; 845*914bffb6SAlexander V. Chernikov } 846*914bffb6SAlexander V. Chernikov 847*914bffb6SAlexander V. Chernikov tfe->af = af; 848*914bffb6SAlexander V. Chernikov 849*914bffb6SAlexander V. Chernikov break; 850*914bffb6SAlexander V. Chernikov 851ac35ff17SAlexander V. Chernikov default: 852ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 853ac35ff17SAlexander V. Chernikov } 854ac35ff17SAlexander V. Chernikov 855ac35ff17SAlexander V. Chernikov tentry->subtype = af; 856ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 857ac35ff17SAlexander V. Chernikov } 858ac35ff17SAlexander V. Chernikov 859ac35ff17SAlexander V. Chernikov static void 860ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 86181d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 862ac35ff17SAlexander V. Chernikov { 863*914bffb6SAlexander V. Chernikov uint8_t type, tflags, vtype; 864ac35ff17SAlexander V. Chernikov int error; 865db785d31SAlexander V. Chernikov char *del; 866ac35ff17SAlexander V. Chernikov 867ac35ff17SAlexander V. Chernikov type = 0; 868*914bffb6SAlexander V. Chernikov tflags = 0; 869ac35ff17SAlexander V. Chernikov vtype = 0; 870ac35ff17SAlexander V. Chernikov 87181d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 87281d3153dSAlexander V. Chernikov 87381d3153dSAlexander V. Chernikov if (error == 0) { 87481d3153dSAlexander V. Chernikov /* Table found. */ 87581d3153dSAlexander V. Chernikov type = xi->type; 876*914bffb6SAlexander V. Chernikov tflags = xi->tflags; 87781d3153dSAlexander V. Chernikov vtype = xi->vtype; 87881d3153dSAlexander V. Chernikov } else { 87981d3153dSAlexander V. Chernikov if (error != ESRCH) 88081d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 88181d3153dSAlexander V. Chernikov oh->ntlv.name); 882ac35ff17SAlexander V. Chernikov /* 88381d3153dSAlexander V. Chernikov * Table does not exist. 88481d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 88581d3153dSAlexander V. Chernikov * before failing. 886ac35ff17SAlexander V. Chernikov */ 887db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 888db785d31SAlexander V. Chernikov *del = '\0'; 889ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 890ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 891ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 892ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 893ac35ff17SAlexander V. Chernikov /* 89481d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 89581d3153dSAlexander V. Chernikov * This should be changed for MFC. 896ac35ff17SAlexander V. Chernikov */ 89781d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 89881d3153dSAlexander V. Chernikov } else { 89981d3153dSAlexander V. Chernikov /* Inknown key */ 90081d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 901db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 90281d3153dSAlexander V. Chernikov } 903db785d31SAlexander V. Chernikov if (del != NULL) 904db785d31SAlexander V. Chernikov *del = '/'; 905ac35ff17SAlexander V. Chernikov } 906ac35ff17SAlexander V. Chernikov 907*914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 908ac35ff17SAlexander V. Chernikov 909ac35ff17SAlexander V. Chernikov *ptype = type; 910ac35ff17SAlexander V. Chernikov *pvtype = vtype; 911ac35ff17SAlexander V. Chernikov } 912ac35ff17SAlexander V. Chernikov 913ac35ff17SAlexander V. Chernikov static void 914ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 915ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 916ac35ff17SAlexander V. Chernikov { 917ac35ff17SAlexander V. Chernikov int code; 918ac35ff17SAlexander V. Chernikov char *p; 919ac35ff17SAlexander V. Chernikov 920ac35ff17SAlexander V. Chernikov switch (vtype) { 921ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 922ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 923ac35ff17SAlexander V. Chernikov if (*p != '\0') 924ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 925ac35ff17SAlexander V. Chernikov break; 926ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 927ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 928ac35ff17SAlexander V. Chernikov break; 929ac35ff17SAlexander V. Chernikov /* Try hostname */ 930ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 931ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 932ac35ff17SAlexander V. Chernikov break; 933ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 934ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 935ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 936ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 937ac35ff17SAlexander V. Chernikov } else { 938ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 939ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 940ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 941ac35ff17SAlexander V. Chernikov } 942ac35ff17SAlexander V. Chernikov tent->value = code; 943ac35ff17SAlexander V. Chernikov break; 944ac35ff17SAlexander V. Chernikov default: 945ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 946ac35ff17SAlexander V. Chernikov } 947ac35ff17SAlexander V. Chernikov } 948f1220db8SAlexander V. Chernikov 949f1220db8SAlexander V. Chernikov /* 950f1220db8SAlexander V. Chernikov * Compare table names. 951f1220db8SAlexander V. Chernikov * Honor number comparison. 952f1220db8SAlexander V. Chernikov */ 953f1220db8SAlexander V. Chernikov static int 954f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 955f1220db8SAlexander V. Chernikov { 956f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 957f1220db8SAlexander V. Chernikov 958f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 959f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 960f1220db8SAlexander V. Chernikov 96168394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 962f1220db8SAlexander V. Chernikov } 963f1220db8SAlexander V. Chernikov 964f1220db8SAlexander V. Chernikov /* 965f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 966f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 967f1220db8SAlexander V. Chernikov * Returns 0 on success. 968f1220db8SAlexander V. Chernikov */ 969f1220db8SAlexander V. Chernikov static int 970f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 971f1220db8SAlexander V. Chernikov { 972f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 973f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 974f1220db8SAlexander V. Chernikov size_t sz; 975f1220db8SAlexander V. Chernikov int i, error; 976f1220db8SAlexander V. Chernikov 977f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 978f1220db8SAlexander V. Chernikov sz = sizeof(req); 979f1220db8SAlexander V. Chernikov 980d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 981f1220db8SAlexander V. Chernikov return (errno); 982f1220db8SAlexander V. Chernikov 983f1220db8SAlexander V. Chernikov sz = req.size; 984f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 985f1220db8SAlexander V. Chernikov return (ENOMEM); 986f1220db8SAlexander V. Chernikov 987f1220db8SAlexander V. Chernikov olh->size = sz; 988d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 989f1220db8SAlexander V. Chernikov free(olh); 990f1220db8SAlexander V. Chernikov return (errno); 991f1220db8SAlexander V. Chernikov } 992f1220db8SAlexander V. Chernikov 993f1220db8SAlexander V. Chernikov if (sort != 0) 994f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 995f1220db8SAlexander V. Chernikov 996f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 997f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 998f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 999f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1000f1220db8SAlexander V. Chernikov } 1001f1220db8SAlexander V. Chernikov 1002f1220db8SAlexander V. Chernikov free(olh); 1003f1220db8SAlexander V. Chernikov 1004f1220db8SAlexander V. Chernikov return (0); 1005f1220db8SAlexander V. Chernikov } 1006f1220db8SAlexander V. Chernikov 1007f1220db8SAlexander V. Chernikov /* 1008f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1009d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 1010d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 1011f1220db8SAlexander V. Chernikov * 1012f1220db8SAlexander V. Chernikov * Returns 0 on success. 1013f1220db8SAlexander V. Chernikov */ 1014f1220db8SAlexander V. Chernikov static int 1015f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 1016f1220db8SAlexander V. Chernikov { 1017f1220db8SAlexander V. Chernikov size_t sz; 101881d3153dSAlexander V. Chernikov int error, c; 1019f1220db8SAlexander V. Chernikov 102081d3153dSAlexander V. Chernikov sz = 0; 102181d3153dSAlexander V. Chernikov for (c = 0; c < 3; c++) { 1022f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 102381d3153dSAlexander V. Chernikov if (sz < i->size) 1024f1220db8SAlexander V. Chernikov sz = i->size; 1025f1220db8SAlexander V. Chernikov 1026d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 102781d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1028d3a4f924SAlexander V. Chernikov 102981d3153dSAlexander V. Chernikov if (error != ENOMEM) 1030f1220db8SAlexander V. Chernikov return (errno); 103181d3153dSAlexander V. Chernikov } 1032f1220db8SAlexander V. Chernikov 103381d3153dSAlexander V. Chernikov return (ENOMEM); 1034f1220db8SAlexander V. Chernikov } 1035f1220db8SAlexander V. Chernikov 1036f1220db8SAlexander V. Chernikov /* 1037f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1038f1220db8SAlexander V. Chernikov */ 1039f1220db8SAlexander V. Chernikov static void 1040f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1041f1220db8SAlexander V. Chernikov { 104281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 104381d3153dSAlexander V. Chernikov uint32_t count; 1044f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1045f1220db8SAlexander V. Chernikov 1046f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 104781d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1048f1220db8SAlexander V. Chernikov 1049f1220db8SAlexander V. Chernikov if (need_header) 1050f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1051f1220db8SAlexander V. Chernikov 1052f1220db8SAlexander V. Chernikov count = i->count; 1053f1220db8SAlexander V. Chernikov while (count > 0) { 105481d3153dSAlexander V. Chernikov table_show_entry(i, tent); 105581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 105681d3153dSAlexander V. Chernikov count--; 105781d3153dSAlexander V. Chernikov } 105881d3153dSAlexander V. Chernikov } 105981d3153dSAlexander V. Chernikov 106081d3153dSAlexander V. Chernikov static void 106181d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 106281d3153dSAlexander V. Chernikov { 1063*914bffb6SAlexander V. Chernikov char *comma, tbuf[128], pval[32]; 1064*914bffb6SAlexander V. Chernikov void *paddr; 106581d3153dSAlexander V. Chernikov uint32_t tval; 1066*914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 106781d3153dSAlexander V. Chernikov 106881d3153dSAlexander V. Chernikov tval = tent->value; 106981d3153dSAlexander V. Chernikov 1070*914bffb6SAlexander V. Chernikov if (co.do_value_as_ip) { 1071*914bffb6SAlexander V. Chernikov tval = htonl(tval); 1072*914bffb6SAlexander V. Chernikov inet_ntop(AF_INET, &tval, pval, sizeof(pval)); 1073*914bffb6SAlexander V. Chernikov } else 1074*914bffb6SAlexander V. Chernikov snprintf(pval, sizeof(pval), "%u", tval); 1075*914bffb6SAlexander V. Chernikov 1076f1220db8SAlexander V. Chernikov switch (i->type) { 1077f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1078f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 107981d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1080*914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1081f1220db8SAlexander V. Chernikov break; 1082f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1083f1220db8SAlexander V. Chernikov /* Interface names */ 1084*914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1085b23d5de9SAlexander V. Chernikov break; 1086b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1087b23d5de9SAlexander V. Chernikov /* numbers */ 1088*914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1089b23d5de9SAlexander V. Chernikov break; 1090*914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1091*914bffb6SAlexander V. Chernikov /* flows */ 1092*914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1093*914bffb6SAlexander V. Chernikov comma = ""; 1094*914bffb6SAlexander V. Chernikov 1095*914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1096*914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1097*914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1098*914bffb6SAlexander V. Chernikov else 1099*914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1100*914bffb6SAlexander V. Chernikov 1101*914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1102*914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1103*914bffb6SAlexander V. Chernikov comma = ","; 1104*914bffb6SAlexander V. Chernikov } 1105*914bffb6SAlexander V. Chernikov 1106*914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1107*914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1108*914bffb6SAlexander V. Chernikov comma = ","; 1109*914bffb6SAlexander V. Chernikov } 1110*914bffb6SAlexander V. Chernikov 1111*914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1112*914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1113*914bffb6SAlexander V. Chernikov comma = ","; 1114*914bffb6SAlexander V. Chernikov } 1115*914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1116*914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1117*914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1118*914bffb6SAlexander V. Chernikov else 1119*914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1120*914bffb6SAlexander V. Chernikov 1121*914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1122*914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1123*914bffb6SAlexander V. Chernikov comma = ","; 1124*914bffb6SAlexander V. Chernikov } 1125*914bffb6SAlexander V. Chernikov 1126*914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1127*914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1128*914bffb6SAlexander V. Chernikov comma = ","; 1129*914bffb6SAlexander V. Chernikov } 1130*914bffb6SAlexander V. Chernikov 1131*914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1132f1220db8SAlexander V. Chernikov } 1133f1220db8SAlexander V. Chernikov } 1134f1220db8SAlexander V. Chernikov 11359d099b4fSAlexander V. Chernikov static int 11369d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 11379d099b4fSAlexander V. Chernikov { 11389d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 11399d099b4fSAlexander V. Chernikov size_t sz; 11409d099b4fSAlexander V. Chernikov int error; 11419d099b4fSAlexander V. Chernikov 11429d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 11439d099b4fSAlexander V. Chernikov sz = sizeof(req); 11449d099b4fSAlexander V. Chernikov 11459d099b4fSAlexander V. Chernikov error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); 11469d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 11479d099b4fSAlexander V. Chernikov return (error); 11489d099b4fSAlexander V. Chernikov 11499d099b4fSAlexander V. Chernikov sz = req.size; 11509d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 11519d099b4fSAlexander V. Chernikov return (ENOMEM); 11529d099b4fSAlexander V. Chernikov 11539d099b4fSAlexander V. Chernikov olh->size = sz; 11549d099b4fSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { 11559d099b4fSAlexander V. Chernikov free(olh); 11569d099b4fSAlexander V. Chernikov return (error); 11579d099b4fSAlexander V. Chernikov } 11589d099b4fSAlexander V. Chernikov 11599d099b4fSAlexander V. Chernikov *polh = olh; 11609d099b4fSAlexander V. Chernikov return (0); 11619d099b4fSAlexander V. Chernikov } 11629d099b4fSAlexander V. Chernikov 11639d099b4fSAlexander V. Chernikov void 11649d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 11659d099b4fSAlexander V. Chernikov { 11669d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 11679d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 11689d099b4fSAlexander V. Chernikov int error, i; 11699d099b4fSAlexander V. Chernikov const char *atype; 11709d099b4fSAlexander V. Chernikov 11719d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 11729d099b4fSAlexander V. Chernikov if (error != 0) 11739d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 11749d099b4fSAlexander V. Chernikov 11759d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 11769d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 11779d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 11789d099b4fSAlexander V. Chernikov atype = "unknown"; 11798ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 11808ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 11819d099b4fSAlexander V. Chernikov 11829d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 11839d099b4fSAlexander V. Chernikov } 11849d099b4fSAlexander V. Chernikov 11859d099b4fSAlexander V. Chernikov free(olh); 11869d099b4fSAlexander V. Chernikov } 11879d099b4fSAlexander V. Chernikov 11886c2997ffSAlexander V. Chernikov int 11896c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 11906c2997ffSAlexander V. Chernikov { 11916c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 11926c2997ffSAlexander V. Chernikov 11936c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 11946c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 11956c2997ffSAlexander V. Chernikov 11966c2997ffSAlexander V. Chernikov if (a->set < b->set) 11976c2997ffSAlexander V. Chernikov return (-1); 11986c2997ffSAlexander V. Chernikov else if (a->set > b->set) 11996c2997ffSAlexander V. Chernikov return (1); 12006c2997ffSAlexander V. Chernikov 12016c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 12026c2997ffSAlexander V. Chernikov return (-1); 12036c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 12046c2997ffSAlexander V. Chernikov return (1); 12056c2997ffSAlexander V. Chernikov 12066c2997ffSAlexander V. Chernikov return (0); 12076c2997ffSAlexander V. Chernikov } 1208563b5ab1SAlexander V. Chernikov 1209563b5ab1SAlexander V. Chernikov int 12106c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1211563b5ab1SAlexander V. Chernikov { 1212563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1213563b5ab1SAlexander V. Chernikov uint16_t key; 1214563b5ab1SAlexander V. Chernikov 1215563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1216563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1217563b5ab1SAlexander V. Chernikov 1218563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1219563b5ab1SAlexander V. Chernikov return (-1); 1220563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1221563b5ab1SAlexander V. Chernikov return (1); 1222563b5ab1SAlexander V. Chernikov 1223563b5ab1SAlexander V. Chernikov return (0); 1224563b5ab1SAlexander V. Chernikov } 1225563b5ab1SAlexander V. Chernikov 1226563b5ab1SAlexander V. Chernikov /* 1227563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1228563b5ab1SAlexander V. Chernikov * Uses the following facts: 1229563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1230563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1231563b5ab1SAlexander V. Chernikov * 1232563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1233563b5ab1SAlexander V. Chernikov */ 1234563b5ab1SAlexander V. Chernikov char * 1235563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1236563b5ab1SAlexander V. Chernikov { 1237563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1238563b5ab1SAlexander V. Chernikov 1239563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 12406c2997ffSAlexander V. Chernikov compare_kntlv); 1241563b5ab1SAlexander V. Chernikov 1242563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1243563b5ab1SAlexander V. Chernikov return (ntlv->name); 1244563b5ab1SAlexander V. Chernikov 1245563b5ab1SAlexander V. Chernikov return (NULL); 1246563b5ab1SAlexander V. Chernikov } 1247563b5ab1SAlexander V. Chernikov 12486c2997ffSAlexander V. Chernikov void 12496c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 12506c2997ffSAlexander V. Chernikov { 12516c2997ffSAlexander V. Chernikov 12526c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 12536c2997ffSAlexander V. Chernikov } 12546c2997ffSAlexander V. Chernikov 12556c2997ffSAlexander V. Chernikov int 12566c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 12576c2997ffSAlexander V. Chernikov { 12586c2997ffSAlexander V. Chernikov int c, i, l; 12596c2997ffSAlexander V. Chernikov 12606c2997ffSAlexander V. Chernikov /* 12616c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 12626c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 1263ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 12646c2997ffSAlexander V. Chernikov */ 12656c2997ffSAlexander V. Chernikov l = strlen(tablename); 12666c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 12676c2997ffSAlexander V. Chernikov return (EINVAL); 12686c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 12696c2997ffSAlexander V. Chernikov c = tablename[i]; 12706c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 12716c2997ffSAlexander V. Chernikov c == '-' || c == '.') 12726c2997ffSAlexander V. Chernikov continue; 12736c2997ffSAlexander V. Chernikov return (EINVAL); 12746c2997ffSAlexander V. Chernikov } 12756c2997ffSAlexander V. Chernikov 1276ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1277ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1278ac35ff17SAlexander V. Chernikov return (EINVAL); 1279ac35ff17SAlexander V. Chernikov 12806c2997ffSAlexander V. Chernikov return (0); 12816c2997ffSAlexander V. Chernikov } 12826c2997ffSAlexander V. Chernikov 1283