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); 57adf3b2b9SAlexander V. Chernikov static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i); 5846d52008SAlexander V. Chernikov static int table_do_swap(ipfw_obj_header *oh, char *second); 59adf3b2b9SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 60adf3b2b9SAlexander V. Chernikov static void table_modify(ipfw_obj_header *oh, int ac, char *av[]); 61adf3b2b9SAlexander V. Chernikov static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 6246d52008SAlexander V. Chernikov static int table_swap(ipfw_obj_header *oh, char *second); 63ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 64f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 65ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, 66ac35ff17SAlexander V. Chernikov uint16_t uidx); 67f1220db8SAlexander V. Chernikov 68f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 69f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 70*720ee730SAlexander V. Chernikov static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); 71f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 7281d3153dSAlexander V. Chernikov static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 73f1220db8SAlexander V. Chernikov 74ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 7581d3153dSAlexander V. Chernikov char *key, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); 76ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 77ac35ff17SAlexander V. Chernikov char *arg, uint8_t type, uint8_t vtype); 78ac35ff17SAlexander V. Chernikov 79f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 80f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 81f1220db8SAlexander V. Chernikov 82f1220db8SAlexander V. Chernikov #ifndef s6_addr32 83f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 84f1220db8SAlexander V. Chernikov #endif 85f1220db8SAlexander V. Chernikov 86ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 87ac35ff17SAlexander V. Chernikov { "cidr", IPFW_TABLE_CIDR }, 88ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 89b23d5de9SAlexander V. Chernikov { "number", IPFW_TABLE_NUMBER }, 90914bffb6SAlexander V. Chernikov { "flow", IPFW_TABLE_FLOW }, 91ac35ff17SAlexander V. Chernikov { NULL, 0 } 92ac35ff17SAlexander V. Chernikov }; 93ac35ff17SAlexander V. Chernikov 94ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 95ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 96ac35ff17SAlexander V. Chernikov { NULL, 0 } 97ac35ff17SAlexander V. Chernikov }; 98ac35ff17SAlexander V. Chernikov 99adf3b2b9SAlexander V. Chernikov static struct _s_x tablefvaltypes[] = { 100adf3b2b9SAlexander V. Chernikov { "ip", IPFW_VFTYPE_IP }, 101adf3b2b9SAlexander V. Chernikov { "number", IPFW_VFTYPE_U32 }, 102adf3b2b9SAlexander V. Chernikov { NULL, 0 } 103adf3b2b9SAlexander V. Chernikov }; 104adf3b2b9SAlexander V. Chernikov 105ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 106ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 107ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 10846d52008SAlexander V. Chernikov { "create", TOK_CREATE }, 109ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 110ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 111adf3b2b9SAlexander V. Chernikov { "modify", TOK_MODIFY }, 11246d52008SAlexander V. Chernikov { "swap", TOK_SWAP }, 113ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 114358b9d09SAlexander V. Chernikov { "detail", TOK_DETAIL }, 115ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 11681d3153dSAlexander V. Chernikov { "lookup", TOK_LOOKUP }, 117ac35ff17SAlexander V. Chernikov { NULL, 0 } 118ac35ff17SAlexander V. Chernikov }; 119ac35ff17SAlexander V. Chernikov 120f1220db8SAlexander V. Chernikov static int 121f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 122f1220db8SAlexander V. Chernikov { 123f1220db8SAlexander V. Chernikov struct hostent *he; 124f1220db8SAlexander V. Chernikov 125f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 126f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 127f1220db8SAlexander V. Chernikov return(-1); 128f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 129f1220db8SAlexander V. Chernikov } 130f1220db8SAlexander V. Chernikov return(0); 131f1220db8SAlexander V. Chernikov } 132f1220db8SAlexander V. Chernikov 133f1220db8SAlexander V. Chernikov /* 134f1220db8SAlexander V. Chernikov * This one handles all table-related commands 135ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 136ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 137ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 138ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 139ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 140ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 141ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 142f1220db8SAlexander V. Chernikov */ 143f1220db8SAlexander V. Chernikov void 144f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 145f1220db8SAlexander V. Chernikov { 146ac35ff17SAlexander V. Chernikov int do_add, is_all; 147ac35ff17SAlexander V. Chernikov int error, tcmd; 148ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 149ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 150f1220db8SAlexander V. Chernikov char *tablename; 151ac35ff17SAlexander V. Chernikov uint32_t set; 152358b9d09SAlexander V. Chernikov void *arg; 153f1220db8SAlexander V. Chernikov 154ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 155ac35ff17SAlexander V. Chernikov is_all = 0; 156ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 157ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 158ac35ff17SAlexander V. Chernikov else 159ac35ff17SAlexander V. Chernikov set = 0; 160f1220db8SAlexander V. Chernikov 161f1220db8SAlexander V. Chernikov ac--; av++; 1629d099b4fSAlexander V. Chernikov NEED1("table needs name"); 163f1220db8SAlexander V. Chernikov tablename = *av; 164f1220db8SAlexander V. Chernikov 165ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 166ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 167ac35ff17SAlexander V. Chernikov oh.idx = 1; 168ac35ff17SAlexander V. Chernikov } else { 169ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 170ac35ff17SAlexander V. Chernikov is_all = 1; 171ac35ff17SAlexander V. Chernikov else 172ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 173ac35ff17SAlexander V. Chernikov } 174ac35ff17SAlexander V. Chernikov ac--; av++; 1759d099b4fSAlexander V. Chernikov NEED1("table needs command"); 176ac35ff17SAlexander V. Chernikov 177ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 178ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 179ac35ff17SAlexander V. Chernikov 180ac35ff17SAlexander V. Chernikov switch (tcmd) { 181ac35ff17SAlexander V. Chernikov case TOK_LIST: 182ac35ff17SAlexander V. Chernikov case TOK_INFO: 183358b9d09SAlexander V. Chernikov case TOK_DETAIL: 184ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 185ac35ff17SAlexander V. Chernikov break; 186ac35ff17SAlexander V. Chernikov default: 187ac35ff17SAlexander V. Chernikov if (is_all != 0) 188ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 189ac35ff17SAlexander V. Chernikov } 190ac35ff17SAlexander V. Chernikov 191ac35ff17SAlexander V. Chernikov switch (tcmd) { 192ac35ff17SAlexander V. Chernikov case TOK_ADD: 193ac35ff17SAlexander V. Chernikov case TOK_DEL: 194f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 195f1220db8SAlexander V. Chernikov ac--; av++; 196ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 197ac35ff17SAlexander V. Chernikov break; 198ac35ff17SAlexander V. Chernikov case TOK_CREATE: 199f1220db8SAlexander V. Chernikov ac--; av++; 200ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 201ac35ff17SAlexander V. Chernikov break; 202adf3b2b9SAlexander V. Chernikov case TOK_MODIFY: 203adf3b2b9SAlexander V. Chernikov ac--; av++; 204adf3b2b9SAlexander V. Chernikov table_modify(&oh, ac, av); 205adf3b2b9SAlexander V. Chernikov break; 206ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 207ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 208ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 209ac35ff17SAlexander V. Chernikov break; 210ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 211f1220db8SAlexander V. Chernikov if (is_all == 0) { 212ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 213f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 214f1220db8SAlexander V. Chernikov tablename); 215f1220db8SAlexander V. Chernikov } else { 216ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 217f1220db8SAlexander V. Chernikov if (error != 0) 218f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 219f1220db8SAlexander V. Chernikov } 220ac35ff17SAlexander V. Chernikov break; 22146d52008SAlexander V. Chernikov case TOK_SWAP: 22246d52008SAlexander V. Chernikov ac--; av++; 22346d52008SAlexander V. Chernikov NEED1("second table name required"); 22446d52008SAlexander V. Chernikov table_swap(&oh, *av); 22546d52008SAlexander V. Chernikov break; 226358b9d09SAlexander V. Chernikov case TOK_DETAIL: 227ac35ff17SAlexander V. Chernikov case TOK_INFO: 228358b9d09SAlexander V. Chernikov arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 229f1220db8SAlexander V. Chernikov if (is_all == 0) { 230ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 231f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 232358b9d09SAlexander V. Chernikov table_show_info(&i, arg); 233f1220db8SAlexander V. Chernikov } else { 234358b9d09SAlexander V. Chernikov error = tables_foreach(table_show_info, arg, 1); 235f1220db8SAlexander V. Chernikov if (error != 0) 236f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 237f1220db8SAlexander V. Chernikov } 238ac35ff17SAlexander V. Chernikov break; 239ac35ff17SAlexander V. Chernikov case TOK_LIST: 240ac35ff17SAlexander V. Chernikov if (is_all == 0) { 241ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 242ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 243ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 244ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 245f1220db8SAlexander V. Chernikov } else { 246ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 247ac35ff17SAlexander V. Chernikov if (error != 0) 248ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 249f1220db8SAlexander V. Chernikov } 250ac35ff17SAlexander V. Chernikov break; 25181d3153dSAlexander V. Chernikov case TOK_LOOKUP: 25281d3153dSAlexander V. Chernikov ac--; av++; 25381d3153dSAlexander V. Chernikov table_lookup(&oh, ac, av); 25481d3153dSAlexander V. Chernikov break; 255f1220db8SAlexander V. Chernikov } 256f1220db8SAlexander V. Chernikov } 257f1220db8SAlexander V. Chernikov 258f1220db8SAlexander V. Chernikov static void 259ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 260f1220db8SAlexander V. Chernikov { 261f1220db8SAlexander V. Chernikov 262563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 263f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 264f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 265ac35ff17SAlexander V. Chernikov ntlv->set = set; 266f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 267f1220db8SAlexander V. Chernikov } 268f1220db8SAlexander V. Chernikov 269f1220db8SAlexander V. Chernikov static void 270f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 271f1220db8SAlexander V. Chernikov { 272f1220db8SAlexander V. Chernikov 273f1220db8SAlexander V. Chernikov oh->idx = 1; 27481d3153dSAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 275ac35ff17SAlexander V. Chernikov } 276ac35ff17SAlexander V. Chernikov 277ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 278ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE }, 279adf3b2b9SAlexander V. Chernikov { "ftype", TOK_FTYPE }, 280ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 281ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 2824c0c07a5SAlexander V. Chernikov { "limit", TOK_LIMIT }, 283ac35ff17SAlexander V. Chernikov { NULL, 0 } 284ac35ff17SAlexander V. Chernikov }; 285ac35ff17SAlexander V. Chernikov 286914bffb6SAlexander V. Chernikov static struct _s_x flowtypecmds[] = { 287914bffb6SAlexander V. Chernikov { "src-ip", IPFW_TFFLAG_SRCIP }, 288914bffb6SAlexander V. Chernikov { "proto", IPFW_TFFLAG_PROTO }, 289914bffb6SAlexander V. Chernikov { "src-port", IPFW_TFFLAG_SRCPORT }, 290914bffb6SAlexander V. Chernikov { "dst-ip", IPFW_TFFLAG_DSTIP }, 291914bffb6SAlexander V. Chernikov { "dst-port", IPFW_TFFLAG_DSTPORT }, 292914bffb6SAlexander V. Chernikov { NULL, 0 } 293914bffb6SAlexander V. Chernikov }; 294914bffb6SAlexander V. Chernikov 295914bffb6SAlexander V. Chernikov int 296914bffb6SAlexander V. Chernikov table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 297914bffb6SAlexander V. Chernikov { 298914bffb6SAlexander V. Chernikov uint8_t fset, fclear; 299914bffb6SAlexander V. Chernikov 300914bffb6SAlexander V. Chernikov /* Parse type options */ 301914bffb6SAlexander V. Chernikov switch(ttype) { 302914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 303914bffb6SAlexander V. Chernikov fset = fclear = 0; 304914bffb6SAlexander V. Chernikov fill_flags(flowtypecmds, p, &fset, 305914bffb6SAlexander V. Chernikov &fclear); 306914bffb6SAlexander V. Chernikov *tflags = fset; 307914bffb6SAlexander V. Chernikov break; 308914bffb6SAlexander V. Chernikov default: 309914bffb6SAlexander V. Chernikov return (EX_USAGE); 310914bffb6SAlexander V. Chernikov } 311914bffb6SAlexander V. Chernikov 312914bffb6SAlexander V. Chernikov return (0); 313914bffb6SAlexander V. Chernikov } 314914bffb6SAlexander V. Chernikov 315914bffb6SAlexander V. Chernikov void 316914bffb6SAlexander V. Chernikov table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 317914bffb6SAlexander V. Chernikov { 318914bffb6SAlexander V. Chernikov const char *tname; 319914bffb6SAlexander V. Chernikov int l; 320914bffb6SAlexander V. Chernikov 321914bffb6SAlexander V. Chernikov if ((tname = match_value(tabletypes, type)) == NULL) 322914bffb6SAlexander V. Chernikov tname = "unknown"; 323914bffb6SAlexander V. Chernikov 324914bffb6SAlexander V. Chernikov l = snprintf(tbuf, size, "%s", tname); 325914bffb6SAlexander V. Chernikov tbuf += l; 326914bffb6SAlexander V. Chernikov size -= l; 327914bffb6SAlexander V. Chernikov 328914bffb6SAlexander V. Chernikov switch(type) { 329914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 330914bffb6SAlexander V. Chernikov if (tflags != 0) { 331914bffb6SAlexander V. Chernikov *tbuf++ = ':'; 332914bffb6SAlexander V. Chernikov l--; 333914bffb6SAlexander V. Chernikov print_flags_buffer(tbuf, size, flowtypecmds, tflags); 334914bffb6SAlexander V. Chernikov } 335914bffb6SAlexander V. Chernikov break; 336914bffb6SAlexander V. Chernikov } 337914bffb6SAlexander V. Chernikov } 338914bffb6SAlexander V. Chernikov 339ac35ff17SAlexander V. Chernikov /* 340ac35ff17SAlexander V. Chernikov * Creates new table 341ac35ff17SAlexander V. Chernikov * 342ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 343ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 344ac35ff17SAlexander V. Chernikov * [ algo algoname ] 345ac35ff17SAlexander V. Chernikov */ 346ac35ff17SAlexander V. Chernikov static void 347ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 348ac35ff17SAlexander V. Chernikov { 349ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 350ac35ff17SAlexander V. Chernikov int error, tcmd, val; 351ac35ff17SAlexander V. Chernikov size_t sz; 352914bffb6SAlexander V. Chernikov char *p; 353ac35ff17SAlexander V. Chernikov char tbuf[128]; 354ac35ff17SAlexander V. Chernikov 355ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 356ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 357ac35ff17SAlexander V. Chernikov 358ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 359ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 360ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 361ac35ff17SAlexander V. Chernikov 362ac35ff17SAlexander V. Chernikov while (ac > 0) { 363ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 364ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 365ac35ff17SAlexander V. Chernikov ac--; av++; 366ac35ff17SAlexander V. Chernikov 367ac35ff17SAlexander V. Chernikov switch (tcmd) { 3684c0c07a5SAlexander V. Chernikov case TOK_LIMIT: 3694c0c07a5SAlexander V. Chernikov NEED1("limit value required"); 3704c0c07a5SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 3714c0c07a5SAlexander V. Chernikov ac--; av++; 3724c0c07a5SAlexander V. Chernikov break; 373ac35ff17SAlexander V. Chernikov case TOK_TYPE: 374ac35ff17SAlexander V. Chernikov NEED1("table type required"); 375914bffb6SAlexander V. Chernikov /* Type may have suboptions after ':' */ 376914bffb6SAlexander V. Chernikov if ((p = strchr(*av, ':')) != NULL) 377914bffb6SAlexander V. Chernikov *p++ = '\0'; 378ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 379914bffb6SAlexander V. Chernikov if (val == -1) { 380914bffb6SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, 381914bffb6SAlexander V. Chernikov ", "); 382914bffb6SAlexander V. Chernikov errx(EX_USAGE, 383914bffb6SAlexander V. Chernikov "Unknown tabletype: %s. Supported: %s", 384ac35ff17SAlexander V. Chernikov *av, tbuf); 385914bffb6SAlexander V. Chernikov } 386914bffb6SAlexander V. Chernikov xi.type = val; 387914bffb6SAlexander V. Chernikov if (p != NULL) { 388914bffb6SAlexander V. Chernikov error = table_parse_type(val, p, &xi.tflags); 389914bffb6SAlexander V. Chernikov if (error != 0) 390914bffb6SAlexander V. Chernikov errx(EX_USAGE, 391914bffb6SAlexander V. Chernikov "Unsupported suboptions: %s", p); 392914bffb6SAlexander V. Chernikov } 393914bffb6SAlexander V. Chernikov ac--; av++; 394ac35ff17SAlexander V. Chernikov break; 395ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 396ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 397ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 398ac35ff17SAlexander V. Chernikov if (val != -1) { 399ac35ff17SAlexander V. Chernikov xi.vtype = val; 400ac35ff17SAlexander V. Chernikov ac--; av++; 401ac35ff17SAlexander V. Chernikov break; 402ac35ff17SAlexander V. Chernikov } 403ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 404ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 405ac35ff17SAlexander V. Chernikov *av, tbuf); 406ac35ff17SAlexander V. Chernikov break; 407adf3b2b9SAlexander V. Chernikov case TOK_FTYPE: 408adf3b2b9SAlexander V. Chernikov NEED1("table value format type required"); 409adf3b2b9SAlexander V. Chernikov val = match_token(tablefvaltypes, *av); 410adf3b2b9SAlexander V. Chernikov if (val != -1) { 411adf3b2b9SAlexander V. Chernikov xi.vftype = val; 412adf3b2b9SAlexander V. Chernikov ac--; av++; 413adf3b2b9SAlexander V. Chernikov break; 414adf3b2b9SAlexander V. Chernikov } 415adf3b2b9SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", "); 416adf3b2b9SAlexander V. Chernikov errx(EX_USAGE, "Unknown format type: %s. Supported: %s", 417adf3b2b9SAlexander V. Chernikov *av, tbuf); 418adf3b2b9SAlexander V. Chernikov break; 419ac35ff17SAlexander V. Chernikov case TOK_ALGO: 420ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 421ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 422ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 423ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 424ac35ff17SAlexander V. Chernikov ac--; av++; 425ac35ff17SAlexander V. Chernikov break; 426ac35ff17SAlexander V. Chernikov } 427ac35ff17SAlexander V. Chernikov } 428ac35ff17SAlexander V. Chernikov 429ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 430ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 431f1220db8SAlexander V. Chernikov } 432f1220db8SAlexander V. Chernikov 433f1220db8SAlexander V. Chernikov /* 434ac35ff17SAlexander V. Chernikov * Creates new table 435ac35ff17SAlexander V. Chernikov * 436ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 437ac35ff17SAlexander V. Chernikov * 438f1220db8SAlexander V. Chernikov * Returns 0 on success. 439f1220db8SAlexander V. Chernikov */ 440f1220db8SAlexander V. Chernikov static int 441ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 442f1220db8SAlexander V. Chernikov { 443ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 444ac35ff17SAlexander V. Chernikov int error; 445f1220db8SAlexander V. Chernikov 446ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 447ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 448ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 449ac35ff17SAlexander V. Chernikov 450ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 451ac35ff17SAlexander V. Chernikov 452ac35ff17SAlexander V. Chernikov return (error); 453ac35ff17SAlexander V. Chernikov } 454ac35ff17SAlexander V. Chernikov 455ac35ff17SAlexander V. Chernikov /* 456adf3b2b9SAlexander V. Chernikov * Modifies existing table 457adf3b2b9SAlexander V. Chernikov * 458adf3b2b9SAlexander V. Chernikov * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ] 459adf3b2b9SAlexander V. Chernikov */ 460adf3b2b9SAlexander V. Chernikov static void 461adf3b2b9SAlexander V. Chernikov table_modify(ipfw_obj_header *oh, int ac, char *av[]) 462adf3b2b9SAlexander V. Chernikov { 463adf3b2b9SAlexander V. Chernikov ipfw_xtable_info xi; 464adf3b2b9SAlexander V. Chernikov int error, tcmd, val; 465adf3b2b9SAlexander V. Chernikov size_t sz; 466adf3b2b9SAlexander V. Chernikov char tbuf[128]; 467adf3b2b9SAlexander V. Chernikov 468adf3b2b9SAlexander V. Chernikov sz = sizeof(tbuf); 469adf3b2b9SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 470adf3b2b9SAlexander V. Chernikov 471adf3b2b9SAlexander V. Chernikov /* Set some defaults to preserve compability */ 472adf3b2b9SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 473adf3b2b9SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 474adf3b2b9SAlexander V. Chernikov 475adf3b2b9SAlexander V. Chernikov while (ac > 0) { 476adf3b2b9SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 477adf3b2b9SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 478adf3b2b9SAlexander V. Chernikov ac--; av++; 479adf3b2b9SAlexander V. Chernikov 480adf3b2b9SAlexander V. Chernikov switch (tcmd) { 481adf3b2b9SAlexander V. Chernikov case TOK_LIMIT: 482adf3b2b9SAlexander V. Chernikov NEED1("limit value required"); 483adf3b2b9SAlexander V. Chernikov xi.limit = strtol(*av, NULL, 10); 484adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_LIMIT; 485adf3b2b9SAlexander V. Chernikov ac--; av++; 486adf3b2b9SAlexander V. Chernikov break; 487adf3b2b9SAlexander V. Chernikov case TOK_FTYPE: 488adf3b2b9SAlexander V. Chernikov NEED1("table value format type required"); 489adf3b2b9SAlexander V. Chernikov val = match_token(tablefvaltypes, *av); 490adf3b2b9SAlexander V. Chernikov if (val != -1) { 491adf3b2b9SAlexander V. Chernikov xi.vftype = val; 492adf3b2b9SAlexander V. Chernikov xi.mflags |= IPFW_TMFLAGS_FTYPE; 493adf3b2b9SAlexander V. Chernikov ac--; av++; 494adf3b2b9SAlexander V. Chernikov break; 495adf3b2b9SAlexander V. Chernikov } 496adf3b2b9SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", "); 497adf3b2b9SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 498adf3b2b9SAlexander V. Chernikov *av, tbuf); 499adf3b2b9SAlexander V. Chernikov break; 500adf3b2b9SAlexander V. Chernikov } 501adf3b2b9SAlexander V. Chernikov } 502adf3b2b9SAlexander V. Chernikov 503adf3b2b9SAlexander V. Chernikov if ((error = table_do_modify(oh, &xi)) != 0) 504adf3b2b9SAlexander V. Chernikov err(EX_OSERR, "Table modification failed"); 505adf3b2b9SAlexander V. Chernikov } 506adf3b2b9SAlexander V. Chernikov 507adf3b2b9SAlexander V. Chernikov /* 508adf3b2b9SAlexander V. Chernikov * Modifies existing table. 509adf3b2b9SAlexander V. Chernikov * 510adf3b2b9SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 511adf3b2b9SAlexander V. Chernikov * 512adf3b2b9SAlexander V. Chernikov * Returns 0 on success. 513adf3b2b9SAlexander V. Chernikov */ 514adf3b2b9SAlexander V. Chernikov static int 515adf3b2b9SAlexander V. Chernikov table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 516adf3b2b9SAlexander V. Chernikov { 517adf3b2b9SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 518adf3b2b9SAlexander V. Chernikov int error; 519adf3b2b9SAlexander V. Chernikov 520adf3b2b9SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 521adf3b2b9SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 522adf3b2b9SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 523adf3b2b9SAlexander V. Chernikov 524adf3b2b9SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 525adf3b2b9SAlexander V. Chernikov 526adf3b2b9SAlexander V. Chernikov return (error); 527adf3b2b9SAlexander V. Chernikov } 528adf3b2b9SAlexander V. Chernikov /* 529ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 530ac35ff17SAlexander V. Chernikov * Returns 0 on success. 531ac35ff17SAlexander V. Chernikov */ 532ac35ff17SAlexander V. Chernikov static int 533ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 534ac35ff17SAlexander V. Chernikov { 535ac35ff17SAlexander V. Chernikov 536ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 537f1220db8SAlexander V. Chernikov return (-1); 538f1220db8SAlexander V. Chernikov 539f1220db8SAlexander V. Chernikov return (0); 540f1220db8SAlexander V. Chernikov } 541f1220db8SAlexander V. Chernikov 542f1220db8SAlexander V. Chernikov /* 543ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 544f1220db8SAlexander V. Chernikov * Returns 0 on success. 545f1220db8SAlexander V. Chernikov */ 546f1220db8SAlexander V. Chernikov static int 547ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 548f1220db8SAlexander V. Chernikov { 549f1220db8SAlexander V. Chernikov 550ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 551f1220db8SAlexander V. Chernikov return (-1); 552f1220db8SAlexander V. Chernikov 553f1220db8SAlexander V. Chernikov return (0); 554f1220db8SAlexander V. Chernikov } 555f1220db8SAlexander V. Chernikov 55646d52008SAlexander V. Chernikov static int 55746d52008SAlexander V. Chernikov table_do_swap(ipfw_obj_header *oh, char *second) 55846d52008SAlexander V. Chernikov { 55946d52008SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 56046d52008SAlexander V. Chernikov int error; 56146d52008SAlexander V. Chernikov 56246d52008SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 56346d52008SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 56446d52008SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 56546d52008SAlexander V. Chernikov table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 56646d52008SAlexander V. Chernikov 56746d52008SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 56846d52008SAlexander V. Chernikov 56946d52008SAlexander V. Chernikov return (error); 57046d52008SAlexander V. Chernikov } 57146d52008SAlexander V. Chernikov 57246d52008SAlexander V. Chernikov /* 57346d52008SAlexander V. Chernikov * Swaps given table with @second one. 57446d52008SAlexander V. Chernikov */ 57546d52008SAlexander V. Chernikov static int 57646d52008SAlexander V. Chernikov table_swap(ipfw_obj_header *oh, char *second) 57746d52008SAlexander V. Chernikov { 57846d52008SAlexander V. Chernikov int error; 57946d52008SAlexander V. Chernikov 58046d52008SAlexander V. Chernikov if (table_check_name(second) != 0) 58146d52008SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", second); 58246d52008SAlexander V. Chernikov 58346d52008SAlexander V. Chernikov error = table_do_swap(oh, second); 58446d52008SAlexander V. Chernikov 58546d52008SAlexander V. Chernikov switch (error) { 58646d52008SAlexander V. Chernikov case EINVAL: 58746d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check types"); 58846d52008SAlexander V. Chernikov case EFBIG: 58946d52008SAlexander V. Chernikov errx(EX_USAGE, "Unable to swap table: check limits"); 59046d52008SAlexander V. Chernikov } 59146d52008SAlexander V. Chernikov 59246d52008SAlexander V. Chernikov return (0); 59346d52008SAlexander V. Chernikov } 59446d52008SAlexander V. Chernikov 59546d52008SAlexander V. Chernikov 596f1220db8SAlexander V. Chernikov /* 597ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 598f1220db8SAlexander V. Chernikov * it inside @i. 599f1220db8SAlexander V. Chernikov * Returns 0 on success. 600f1220db8SAlexander V. Chernikov */ 601f1220db8SAlexander V. Chernikov static int 602ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 603f1220db8SAlexander V. Chernikov { 604f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 605ac35ff17SAlexander V. Chernikov int error; 606f1220db8SAlexander V. Chernikov size_t sz; 607f1220db8SAlexander V. Chernikov 608f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 609f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 610ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 611f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 612f1220db8SAlexander V. Chernikov 613ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 614ac35ff17SAlexander V. Chernikov return (error); 615f1220db8SAlexander V. Chernikov 616f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 617ac35ff17SAlexander V. Chernikov return (EINVAL); 618f1220db8SAlexander V. Chernikov 619f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 620f1220db8SAlexander V. Chernikov 621f1220db8SAlexander V. Chernikov return (0); 622f1220db8SAlexander V. Chernikov } 623f1220db8SAlexander V. Chernikov 6245f379342SAlexander V. Chernikov static struct _s_x tablealgoclass[] = { 6255f379342SAlexander V. Chernikov { "hash", IPFW_TACLASS_HASH }, 6265f379342SAlexander V. Chernikov { "array", IPFW_TACLASS_ARRAY }, 6275f379342SAlexander V. Chernikov { "radix", IPFW_TACLASS_RADIX }, 6285f379342SAlexander V. Chernikov { NULL, 0 } 6295f379342SAlexander V. Chernikov }; 6305f379342SAlexander V. Chernikov 6315f379342SAlexander V. Chernikov struct ta_cldata { 6325f379342SAlexander V. Chernikov uint8_t taclass; 6335f379342SAlexander V. Chernikov uint8_t spare4; 6345f379342SAlexander V. Chernikov uint16_t itemsize; 6355f379342SAlexander V. Chernikov uint16_t itemsize6; 6365f379342SAlexander V. Chernikov uint32_t size; 6375f379342SAlexander V. Chernikov uint32_t count; 6385f379342SAlexander V. Chernikov }; 6395f379342SAlexander V. Chernikov 6405f379342SAlexander V. Chernikov /* 6415f379342SAlexander V. Chernikov * Print global/per-AF table @i algorithm info. 6425f379342SAlexander V. Chernikov */ 6435f379342SAlexander V. Chernikov static void 6445f379342SAlexander V. Chernikov table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 6455f379342SAlexander V. Chernikov const char *af, const char *taclass) 6465f379342SAlexander V. Chernikov { 6475f379342SAlexander V. Chernikov 6485f379342SAlexander V. Chernikov switch (d->taclass) { 6495f379342SAlexander V. Chernikov case IPFW_TACLASS_HASH: 6505f379342SAlexander V. Chernikov case IPFW_TACLASS_ARRAY: 6515f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 6525f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 6535f379342SAlexander V. Chernikov printf(" size: %u items: %u itemsize: %u\n", 6545f379342SAlexander V. Chernikov d->size, d->count, d->itemsize); 6555f379342SAlexander V. Chernikov else 6565f379342SAlexander V. Chernikov printf(" size: %u items: %u " 6575f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 6585f379342SAlexander V. Chernikov d->size, d->count, 6595f379342SAlexander V. Chernikov d->itemsize, d->itemsize6); 6605f379342SAlexander V. Chernikov break; 6615f379342SAlexander V. Chernikov case IPFW_TACLASS_RADIX: 6625f379342SAlexander V. Chernikov printf(" %salgorithm %s info\n", af, taclass); 6635f379342SAlexander V. Chernikov if (d->itemsize == d->itemsize6) 6645f379342SAlexander V. Chernikov printf(" items: %u itemsize: %u\n", 6655f379342SAlexander V. Chernikov d->count, d->itemsize); 6665f379342SAlexander V. Chernikov else 6675f379342SAlexander V. Chernikov printf(" items: %u " 6685f379342SAlexander V. Chernikov "itemsize4: %u itemsize6: %u\n", 6695f379342SAlexander V. Chernikov d->count, d->itemsize, d->itemsize6); 6705f379342SAlexander V. Chernikov break; 6715f379342SAlexander V. Chernikov default: 6725f379342SAlexander V. Chernikov printf(" algo class: %s\n", taclass); 6735f379342SAlexander V. Chernikov } 6745f379342SAlexander V. Chernikov } 6755f379342SAlexander V. Chernikov 676f1220db8SAlexander V. Chernikov /* 677f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 678f1220db8SAlexander V. Chernikov */ 679f1220db8SAlexander V. Chernikov static int 680f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 681f1220db8SAlexander V. Chernikov { 682adf3b2b9SAlexander V. Chernikov const char *vtype, *vftype; 6835f379342SAlexander V. Chernikov ipfw_ta_tinfo *tainfo; 6845f379342SAlexander V. Chernikov int afdata, afitem; 6855f379342SAlexander V. Chernikov struct ta_cldata d; 686adf3b2b9SAlexander V. Chernikov char ttype[64], tvtype[64]; 687f1220db8SAlexander V. Chernikov 688914bffb6SAlexander V. Chernikov table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 689ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 690ac35ff17SAlexander V. Chernikov vtype = "unknown"; 691adf3b2b9SAlexander V. Chernikov if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL) 692adf3b2b9SAlexander V. Chernikov vftype = "unknown"; 693adf3b2b9SAlexander V. Chernikov if (strcmp(vtype, vftype) != 0) 694adf3b2b9SAlexander V. Chernikov snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype); 695adf3b2b9SAlexander V. Chernikov else 696adf3b2b9SAlexander V. Chernikov snprintf(tvtype, sizeof(tvtype), "%s", vtype); 697ac35ff17SAlexander V. Chernikov 698914bffb6SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 699914bffb6SAlexander V. Chernikov printf(" kindex: %d, type: %s\n", i->kidx, ttype); 700adf3b2b9SAlexander V. Chernikov printf(" valtype: %s, references: %u\n", tvtype, i->refcnt); 7019d099b4fSAlexander V. Chernikov printf(" algorithm: %s\n", i->algoname); 702f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 7034c0c07a5SAlexander V. Chernikov if (i->limit > 0) 7044c0c07a5SAlexander V. Chernikov printf(" limit: %u\n", i->limit); 705f1220db8SAlexander V. Chernikov 706358b9d09SAlexander V. Chernikov /* Print algo-specific info if requested & set */ 707358b9d09SAlexander V. Chernikov if (arg == NULL) 708358b9d09SAlexander V. Chernikov return (0); 709358b9d09SAlexander V. Chernikov 7105f379342SAlexander V. Chernikov if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 7115f379342SAlexander V. Chernikov return (0); 7125f379342SAlexander V. Chernikov tainfo = &i->ta_info; 7135f379342SAlexander V. Chernikov 7145f379342SAlexander V. Chernikov afdata = 0; 7155f379342SAlexander V. Chernikov afitem = 0; 7165f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 7175f379342SAlexander V. Chernikov afdata = 1; 7185f379342SAlexander V. Chernikov if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 7195f379342SAlexander V. Chernikov afitem = 1; 7205f379342SAlexander V. Chernikov 7215f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7225f379342SAlexander V. Chernikov d.taclass = tainfo->taclass4; 7235f379342SAlexander V. Chernikov d.size = tainfo->size4; 7245f379342SAlexander V. Chernikov d.count = tainfo->count4; 7255f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize4; 7265f379342SAlexander V. Chernikov if (afdata == 0 && afitem != 0) 7275f379342SAlexander V. Chernikov d.itemsize6 = tainfo->itemsize6; 7285f379342SAlexander V. Chernikov else 7295f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7305f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7315f379342SAlexander V. Chernikov vtype = "unknown"; 7325f379342SAlexander V. Chernikov 7335f379342SAlexander V. Chernikov if (afdata == 0) { 7345f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "", vtype); 7355f379342SAlexander V. Chernikov } else { 7365f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv4 ", vtype); 7375f379342SAlexander V. Chernikov memset(&d, 0, sizeof(d)); 7385f379342SAlexander V. Chernikov d.taclass = tainfo->taclass6; 7395f379342SAlexander V. Chernikov if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 7405f379342SAlexander V. Chernikov vtype = "unknown"; 7415f379342SAlexander V. Chernikov d.size = tainfo->size6; 7425f379342SAlexander V. Chernikov d.count = tainfo->count6; 7435f379342SAlexander V. Chernikov d.itemsize = tainfo->itemsize6; 7445f379342SAlexander V. Chernikov d.itemsize6 = d.itemsize; 7455f379342SAlexander V. Chernikov table_show_tainfo(i, &d, "IPv6 ", vtype); 7465f379342SAlexander V. Chernikov } 7475f379342SAlexander V. Chernikov 748f1220db8SAlexander V. Chernikov return (0); 749f1220db8SAlexander V. Chernikov } 750f1220db8SAlexander V. Chernikov 751f1220db8SAlexander V. Chernikov 752f1220db8SAlexander V. Chernikov /* 753f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 754f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 755f1220db8SAlexander V. Chernikov */ 756f1220db8SAlexander V. Chernikov 757f1220db8SAlexander V. Chernikov static int 758f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 759f1220db8SAlexander V. Chernikov { 760f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 76181d3153dSAlexander V. Chernikov int error; 762f1220db8SAlexander V. Chernikov 763*720ee730SAlexander V. Chernikov if ((error = table_do_get_list(i, &oh)) != 0) { 76481d3153dSAlexander V. Chernikov err(EX_OSERR, "Error requesting table %s list", i->tablename); 76581d3153dSAlexander V. Chernikov return (error); 76681d3153dSAlexander V. Chernikov } 76781d3153dSAlexander V. Chernikov 768f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 769f1220db8SAlexander V. Chernikov 770f1220db8SAlexander V. Chernikov free(oh); 771f1220db8SAlexander V. Chernikov return (0); 772f1220db8SAlexander V. Chernikov } 773f1220db8SAlexander V. Chernikov 774f1220db8SAlexander V. Chernikov static int 775f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 776f1220db8SAlexander V. Chernikov { 777ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 778f1220db8SAlexander V. Chernikov 779ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 780ac35ff17SAlexander V. Chernikov 781ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 782ac35ff17SAlexander V. Chernikov 783ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 784f1220db8SAlexander V. Chernikov } 785f1220db8SAlexander V. Chernikov 786ac35ff17SAlexander V. Chernikov static int 787ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 788ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 789ac35ff17SAlexander V. Chernikov { 790db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 791db785d31SAlexander V. Chernikov char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 792ac35ff17SAlexander V. Chernikov int error; 793ac35ff17SAlexander V. Chernikov 794ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 795ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 796ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 797ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 798ac35ff17SAlexander V. Chernikov 799db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 800db785d31SAlexander V. Chernikov ctlv->count = 1; 801db785d31SAlexander V. Chernikov ctlv->head.length = sizeof(*ctlv) + sizeof(*tent); 802db785d31SAlexander V. Chernikov 803db785d31SAlexander V. Chernikov memcpy(ctlv + 1, tent, sizeof(*tent)); 804db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 805ac35ff17SAlexander V. Chernikov if (update != 0) 80681d3153dSAlexander V. Chernikov tent->head.flags |= IPFW_TF_UPDATE; 807ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 808ac35ff17SAlexander V. Chernikov 809ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 810ac35ff17SAlexander V. Chernikov 811ac35ff17SAlexander V. Chernikov return (error); 812ac35ff17SAlexander V. Chernikov } 813ac35ff17SAlexander V. Chernikov 814ac35ff17SAlexander V. Chernikov static void 815ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 816ac35ff17SAlexander V. Chernikov { 817ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 81881d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 819ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 8204c0c07a5SAlexander V. Chernikov int cmd, error; 8214c0c07a5SAlexander V. Chernikov char *texterr, *etxt; 822ac35ff17SAlexander V. Chernikov 823ac35ff17SAlexander V. Chernikov if (ac == 0) 824ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 825ac35ff17SAlexander V. Chernikov 826ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 827ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 828ac35ff17SAlexander V. Chernikov tent.idx = 1; 829ac35ff17SAlexander V. Chernikov 83081d3153dSAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype, &xi); 831db785d31SAlexander V. Chernikov 832db785d31SAlexander V. Chernikov /* 833db785d31SAlexander V. Chernikov * compability layer: auto-create table if not exists 834db785d31SAlexander V. Chernikov */ 835db785d31SAlexander V. Chernikov if (xi.tablename[0] == '\0') { 836db785d31SAlexander V. Chernikov xi.type = type; 837db785d31SAlexander V. Chernikov xi.vtype = vtype; 838db785d31SAlexander V. Chernikov strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); 839db785d31SAlexander V. Chernikov fprintf(stderr, "DEPRECATED: inserting data info non-existent " 840db785d31SAlexander V. Chernikov "table %s. (auto-created)\n", xi.tablename); 841db785d31SAlexander V. Chernikov table_do_create(oh, &xi); 842db785d31SAlexander V. Chernikov } 843db785d31SAlexander V. Chernikov 844ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 845ac35ff17SAlexander V. Chernikov ac--; av++; 846ac35ff17SAlexander V. Chernikov 847ac35ff17SAlexander V. Chernikov if (add != 0) { 848ac35ff17SAlexander V. Chernikov if (ac > 0) 849ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 850ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 8514c0c07a5SAlexander V. Chernikov texterr = "Adding record failed"; 852ac35ff17SAlexander V. Chernikov } else { 853ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 8544c0c07a5SAlexander V. Chernikov texterr = "Deleting record failed"; 855ac35ff17SAlexander V. Chernikov } 856ac35ff17SAlexander V. Chernikov 8574c0c07a5SAlexander V. Chernikov if ((error = table_do_modify_record(cmd, oh, &tent, update)) == 0) 8584c0c07a5SAlexander V. Chernikov return; 8594c0c07a5SAlexander V. Chernikov 8604c0c07a5SAlexander V. Chernikov /* Try to provide more human-readable error */ 8614c0c07a5SAlexander V. Chernikov switch (error) { 8624c0c07a5SAlexander V. Chernikov case EEXIST: 8634c0c07a5SAlexander V. Chernikov etxt = "record already exists"; 8644c0c07a5SAlexander V. Chernikov break; 8654c0c07a5SAlexander V. Chernikov case EFBIG: 8664c0c07a5SAlexander V. Chernikov etxt = "limit hit"; 8674c0c07a5SAlexander V. Chernikov break; 8684c0c07a5SAlexander V. Chernikov case ESRCH: 8694c0c07a5SAlexander V. Chernikov etxt = "table not found"; 8704c0c07a5SAlexander V. Chernikov break; 8714c0c07a5SAlexander V. Chernikov case ENOENT: 8724c0c07a5SAlexander V. Chernikov etxt = "record not found"; 8734c0c07a5SAlexander V. Chernikov break; 8744c0c07a5SAlexander V. Chernikov default: 8754c0c07a5SAlexander V. Chernikov etxt = strerror(error); 8764c0c07a5SAlexander V. Chernikov } 8774c0c07a5SAlexander V. Chernikov 8784c0c07a5SAlexander V. Chernikov errx(EX_OSERR, "%s: %s", texterr, etxt); 879ac35ff17SAlexander V. Chernikov } 880ac35ff17SAlexander V. Chernikov 88181d3153dSAlexander V. Chernikov static int 88281d3153dSAlexander V. Chernikov table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 88381d3153dSAlexander V. Chernikov ipfw_obj_tentry *xtent) 88481d3153dSAlexander V. Chernikov { 88581d3153dSAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 88681d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 88781d3153dSAlexander V. Chernikov uint8_t type, vtype; 88881d3153dSAlexander V. Chernikov int error; 88981d3153dSAlexander V. Chernikov size_t sz; 89081d3153dSAlexander V. Chernikov 89181d3153dSAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 89281d3153dSAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 89381d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 89481d3153dSAlexander V. Chernikov 89581d3153dSAlexander V. Chernikov memset(tent, 0, sizeof(*tent)); 89681d3153dSAlexander V. Chernikov tent->head.length = sizeof(*tent); 89781d3153dSAlexander V. Chernikov tent->idx = 1; 89881d3153dSAlexander V. Chernikov 89981d3153dSAlexander V. Chernikov tentry_fill_key(oh, tent, key, &type, &vtype, xi); 90081d3153dSAlexander V. Chernikov oh->ntlv.type = type; 90181d3153dSAlexander V. Chernikov 90281d3153dSAlexander V. Chernikov sz = sizeof(xbuf); 90381d3153dSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz)) != 0) 90481d3153dSAlexander V. Chernikov return (error); 90581d3153dSAlexander V. Chernikov 90681d3153dSAlexander V. Chernikov if (sz < sizeof(xbuf)) 90781d3153dSAlexander V. Chernikov return (EINVAL); 90881d3153dSAlexander V. Chernikov 90981d3153dSAlexander V. Chernikov *xtent = *tent; 91081d3153dSAlexander V. Chernikov 91181d3153dSAlexander V. Chernikov return (0); 91281d3153dSAlexander V. Chernikov } 91381d3153dSAlexander V. Chernikov 91481d3153dSAlexander V. Chernikov static void 91581d3153dSAlexander V. Chernikov table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 91681d3153dSAlexander V. Chernikov { 91781d3153dSAlexander V. Chernikov ipfw_obj_tentry xtent; 91881d3153dSAlexander V. Chernikov ipfw_xtable_info xi; 919914bffb6SAlexander V. Chernikov char key[64]; 92081d3153dSAlexander V. Chernikov int error; 92181d3153dSAlexander V. Chernikov 92281d3153dSAlexander V. Chernikov if (ac == 0) 92381d3153dSAlexander V. Chernikov errx(EX_USAGE, "address required"); 92481d3153dSAlexander V. Chernikov 925914bffb6SAlexander V. Chernikov strlcpy(key, *av, sizeof(key)); 926914bffb6SAlexander V. Chernikov 927914bffb6SAlexander V. Chernikov error = table_do_lookup(oh, key, &xi, &xtent); 92881d3153dSAlexander V. Chernikov 92981d3153dSAlexander V. Chernikov switch (error) { 93081d3153dSAlexander V. Chernikov case 0: 93181d3153dSAlexander V. Chernikov break; 93281d3153dSAlexander V. Chernikov case ESRCH: 93381d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 93481d3153dSAlexander V. Chernikov case ENOENT: 93581d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Entry %s not found", *av); 93681d3153dSAlexander V. Chernikov case ENOTSUP: 93781d3153dSAlexander V. Chernikov errx(EX_UNAVAILABLE, "Table %s algo does not support " 93881d3153dSAlexander V. Chernikov "\"lookup\" method", oh->ntlv.name); 93981d3153dSAlexander V. Chernikov default: 94081d3153dSAlexander V. Chernikov err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 94181d3153dSAlexander V. Chernikov } 94281d3153dSAlexander V. Chernikov 94381d3153dSAlexander V. Chernikov table_show_entry(&xi, &xtent); 94481d3153dSAlexander V. Chernikov } 945ac35ff17SAlexander V. Chernikov 946ac35ff17SAlexander V. Chernikov static void 947914bffb6SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 948914bffb6SAlexander V. Chernikov uint8_t tflags) 949ac35ff17SAlexander V. Chernikov { 950914bffb6SAlexander V. Chernikov char *p, *pp; 951ac35ff17SAlexander V. Chernikov int mask, af; 952914bffb6SAlexander V. Chernikov struct in6_addr *paddr, tmp; 953914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 954ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 955914bffb6SAlexander V. Chernikov uint16_t port; 956914bffb6SAlexander V. Chernikov struct protoent *pent; 957914bffb6SAlexander V. Chernikov struct servent *sent; 958ac35ff17SAlexander V. Chernikov int masklen; 959ac35ff17SAlexander V. Chernikov 960ac35ff17SAlexander V. Chernikov masklen = 0; 961ac35ff17SAlexander V. Chernikov af = 0; 962ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 963ac35ff17SAlexander V. Chernikov 964ac35ff17SAlexander V. Chernikov switch (type) { 965ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 966ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 967ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 968ac35ff17SAlexander V. Chernikov *p = '\0'; 969ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 970ac35ff17SAlexander V. Chernikov } 971ac35ff17SAlexander V. Chernikov 972ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 973ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 974ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 975ac35ff17SAlexander V. Chernikov p + 1); 976ac35ff17SAlexander V. Chernikov 977ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 978ac35ff17SAlexander V. Chernikov af = AF_INET; 979ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 980ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 981ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 982ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 983ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 984ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 985ac35ff17SAlexander V. Chernikov p + 1); 986ac35ff17SAlexander V. Chernikov 987ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 988ac35ff17SAlexander V. Chernikov af = AF_INET6; 989ac35ff17SAlexander V. Chernikov } else { 990ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 991ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 992ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 993ac35ff17SAlexander V. Chernikov 994ac35ff17SAlexander V. Chernikov masklen = 32; 995ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 996ac35ff17SAlexander V. Chernikov af = AF_INET; 997ac35ff17SAlexander V. Chernikov } 998ac35ff17SAlexander V. Chernikov break; 999ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1000ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 1001ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1002ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 1003ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 1004ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 1005ac35ff17SAlexander V. Chernikov break; 1006b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1007ac35ff17SAlexander V. Chernikov /* Port or any other key */ 1008ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 1009ac35ff17SAlexander V. Chernikov if (*p != '\0') 1010ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 1011ac35ff17SAlexander V. Chernikov 1012ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 1013ac35ff17SAlexander V. Chernikov *pkey = key; 1014ac35ff17SAlexander V. Chernikov masklen = 32; 1015ac35ff17SAlexander V. Chernikov break; 1016914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1017914bffb6SAlexander V. Chernikov /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1018914bffb6SAlexander V. Chernikov tfe = &tentry->k.flow; 1019914bffb6SAlexander V. Chernikov af = 0; 1020914bffb6SAlexander V. Chernikov 1021914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1022914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1023914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1024914bffb6SAlexander V. Chernikov *p++ = '\0'; 1025914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1026914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1027914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1028914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1029914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1030914bffb6SAlexander V. Chernikov af = AF_INET; 1031914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.sip, &tmp, 4); 1032914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1033914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1034914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1035914bffb6SAlexander V. Chernikov "Inconsistent address family\n"); 1036914bffb6SAlexander V. Chernikov af = AF_INET6; 1037914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.sip6, &tmp, 16); 1038914bffb6SAlexander V. Chernikov } 1039914bffb6SAlexander V. Chernikov 1040914bffb6SAlexander V. Chernikov arg = p; 1041914bffb6SAlexander V. Chernikov } 1042914bffb6SAlexander V. Chernikov 1043914bffb6SAlexander V. Chernikov /* Handle <proto-num|proto-name> */ 1044914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 1045914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1046914bffb6SAlexander V. Chernikov *p++ = '\0'; 1047914bffb6SAlexander V. Chernikov 1048914bffb6SAlexander V. Chernikov key = strtol(arg, &pp, 10); 1049914bffb6SAlexander V. Chernikov if (*pp != '\0') { 1050914bffb6SAlexander V. Chernikov if ((pent = getprotobyname(arg)) == NULL) 1051914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown proto: %s", 1052914bffb6SAlexander V. Chernikov arg); 1053914bffb6SAlexander V. Chernikov else 1054914bffb6SAlexander V. Chernikov key = pent->p_proto; 1055914bffb6SAlexander V. Chernikov } 1056914bffb6SAlexander V. Chernikov 1057914bffb6SAlexander V. Chernikov if (key > 255) 1058914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Bad protocol number: %u",key); 1059914bffb6SAlexander V. Chernikov 1060914bffb6SAlexander V. Chernikov tfe->proto = key; 1061914bffb6SAlexander V. Chernikov 1062914bffb6SAlexander V. Chernikov arg = p; 1063914bffb6SAlexander V. Chernikov } 1064914bffb6SAlexander V. Chernikov 1065914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1066914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1067914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1068914bffb6SAlexander V. Chernikov *p++ = '\0'; 1069914bffb6SAlexander V. Chernikov 1070914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1071914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1072914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1073914bffb6SAlexander V. Chernikov arg); 1074914bffb6SAlexander V. Chernikov else 1075914bffb6SAlexander V. Chernikov key = sent->s_port; 1076914bffb6SAlexander V. Chernikov } 1077914bffb6SAlexander V. Chernikov 1078914bffb6SAlexander V. Chernikov tfe->sport = port; 1079914bffb6SAlexander V. Chernikov 1080914bffb6SAlexander V. Chernikov arg = p; 1081914bffb6SAlexander V. Chernikov } 1082914bffb6SAlexander V. Chernikov 1083914bffb6SAlexander V. Chernikov /* Handle <ipv4|ipv6>*/ 1084914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 1085914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1086914bffb6SAlexander V. Chernikov *p++ = '\0'; 1087914bffb6SAlexander V. Chernikov /* Determine family using temporary storage */ 1088914bffb6SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tmp) == 1) { 1089914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET) 1090914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1091914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1092914bffb6SAlexander V. Chernikov af = AF_INET; 1093914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a4.dip, &tmp, 4); 1094914bffb6SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1095914bffb6SAlexander V. Chernikov if (af != 0 && af != AF_INET6) 1096914bffb6SAlexander V. Chernikov errx(EX_DATAERR, 1097914bffb6SAlexander V. Chernikov "Inconsistent address family"); 1098914bffb6SAlexander V. Chernikov af = AF_INET6; 1099914bffb6SAlexander V. Chernikov memcpy(&tfe->a.a6.dip6, &tmp, 16); 1100914bffb6SAlexander V. Chernikov } 1101914bffb6SAlexander V. Chernikov 1102914bffb6SAlexander V. Chernikov arg = p; 1103914bffb6SAlexander V. Chernikov } 1104914bffb6SAlexander V. Chernikov 1105914bffb6SAlexander V. Chernikov /* Handle <port-num|service-name> */ 1106914bffb6SAlexander V. Chernikov if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1107914bffb6SAlexander V. Chernikov if ((p = strchr(arg, ',')) != NULL) 1108914bffb6SAlexander V. Chernikov *p++ = '\0'; 1109914bffb6SAlexander V. Chernikov 1110914bffb6SAlexander V. Chernikov if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1111914bffb6SAlexander V. Chernikov if ((sent = getservbyname(arg, NULL)) == NULL) 1112914bffb6SAlexander V. Chernikov errx(EX_DATAERR, "Unknown service: %s", 1113914bffb6SAlexander V. Chernikov arg); 1114914bffb6SAlexander V. Chernikov else 1115914bffb6SAlexander V. Chernikov key = sent->s_port; 1116914bffb6SAlexander V. Chernikov } 1117914bffb6SAlexander V. Chernikov 1118914bffb6SAlexander V. Chernikov tfe->dport = port; 1119914bffb6SAlexander V. Chernikov 1120914bffb6SAlexander V. Chernikov arg = p; 1121914bffb6SAlexander V. Chernikov } 1122914bffb6SAlexander V. Chernikov 1123914bffb6SAlexander V. Chernikov tfe->af = af; 1124914bffb6SAlexander V. Chernikov 1125914bffb6SAlexander V. Chernikov break; 1126914bffb6SAlexander V. Chernikov 1127ac35ff17SAlexander V. Chernikov default: 1128ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 1129ac35ff17SAlexander V. Chernikov } 1130ac35ff17SAlexander V. Chernikov 1131ac35ff17SAlexander V. Chernikov tentry->subtype = af; 1132ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 1133ac35ff17SAlexander V. Chernikov } 1134ac35ff17SAlexander V. Chernikov 1135ac35ff17SAlexander V. Chernikov static void 1136ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 113781d3153dSAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) 1138ac35ff17SAlexander V. Chernikov { 1139914bffb6SAlexander V. Chernikov uint8_t type, tflags, vtype; 1140ac35ff17SAlexander V. Chernikov int error; 1141db785d31SAlexander V. Chernikov char *del; 1142ac35ff17SAlexander V. Chernikov 1143ac35ff17SAlexander V. Chernikov type = 0; 1144914bffb6SAlexander V. Chernikov tflags = 0; 1145ac35ff17SAlexander V. Chernikov vtype = 0; 1146ac35ff17SAlexander V. Chernikov 114781d3153dSAlexander V. Chernikov error = table_get_info(oh, xi); 114881d3153dSAlexander V. Chernikov 114981d3153dSAlexander V. Chernikov if (error == 0) { 115081d3153dSAlexander V. Chernikov /* Table found. */ 115181d3153dSAlexander V. Chernikov type = xi->type; 1152914bffb6SAlexander V. Chernikov tflags = xi->tflags; 115381d3153dSAlexander V. Chernikov vtype = xi->vtype; 115481d3153dSAlexander V. Chernikov } else { 115581d3153dSAlexander V. Chernikov if (error != ESRCH) 115681d3153dSAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 115781d3153dSAlexander V. Chernikov oh->ntlv.name); 1158ac35ff17SAlexander V. Chernikov /* 115981d3153dSAlexander V. Chernikov * Table does not exist. 116081d3153dSAlexander V. Chernikov * Compability layer: try to interpret data as CIDR 116181d3153dSAlexander V. Chernikov * before failing. 1162ac35ff17SAlexander V. Chernikov */ 1163db785d31SAlexander V. Chernikov if ((del = strchr(key, '/')) != NULL) 1164db785d31SAlexander V. Chernikov *del = '\0'; 1165ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 1166ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 1167ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 1168ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 1169ac35ff17SAlexander V. Chernikov /* 117081d3153dSAlexander V. Chernikov * XXX: Value type is forced to be u32. 117181d3153dSAlexander V. Chernikov * This should be changed for MFC. 1172ac35ff17SAlexander V. Chernikov */ 117381d3153dSAlexander V. Chernikov vtype = IPFW_VTYPE_U32; 117481d3153dSAlexander V. Chernikov } else { 117581d3153dSAlexander V. Chernikov /* Inknown key */ 117681d3153dSAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot guess " 1177db785d31SAlexander V. Chernikov "key '%s' type", oh->ntlv.name, key); 117881d3153dSAlexander V. Chernikov } 1179db785d31SAlexander V. Chernikov if (del != NULL) 1180db785d31SAlexander V. Chernikov *del = '/'; 1181ac35ff17SAlexander V. Chernikov } 1182ac35ff17SAlexander V. Chernikov 1183914bffb6SAlexander V. Chernikov tentry_fill_key_type(key, tent, type, tflags); 1184ac35ff17SAlexander V. Chernikov 1185ac35ff17SAlexander V. Chernikov *ptype = type; 1186ac35ff17SAlexander V. Chernikov *pvtype = vtype; 1187ac35ff17SAlexander V. Chernikov } 1188ac35ff17SAlexander V. Chernikov 1189ac35ff17SAlexander V. Chernikov static void 1190ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1191ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 1192ac35ff17SAlexander V. Chernikov { 1193adf3b2b9SAlexander V. Chernikov uint32_t val; 1194ac35ff17SAlexander V. Chernikov char *p; 1195ac35ff17SAlexander V. Chernikov 1196adf3b2b9SAlexander V. Chernikov /* Try to interpret as number first */ 1197adf3b2b9SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1198adf3b2b9SAlexander V. Chernikov if (*p == '\0') 1199adf3b2b9SAlexander V. Chernikov return; 1200adf3b2b9SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &val) == 1) { 1201adf3b2b9SAlexander V. Chernikov tent->value = ntohl(val); 1202adf3b2b9SAlexander V. Chernikov return; 1203adf3b2b9SAlexander V. Chernikov } 1204adf3b2b9SAlexander V. Chernikov /* Try hostname */ 1205adf3b2b9SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) == 0) 1206adf3b2b9SAlexander V. Chernikov return; 1207adf3b2b9SAlexander V. Chernikov errx(EX_OSERR, "Unable to parse value %s", arg); 1208adf3b2b9SAlexander V. Chernikov #if 0 1209ac35ff17SAlexander V. Chernikov switch (vtype) { 1210ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 1211ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 1212ac35ff17SAlexander V. Chernikov if (*p != '\0') 1213ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 1214ac35ff17SAlexander V. Chernikov break; 1215ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 1216ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 1217ac35ff17SAlexander V. Chernikov break; 1218ac35ff17SAlexander V. Chernikov /* Try hostname */ 1219ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 1220ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 1221ac35ff17SAlexander V. Chernikov break; 1222ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 1223ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 1224ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 1225ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 1226ac35ff17SAlexander V. Chernikov } else { 1227ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 1228ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 1229ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 1230ac35ff17SAlexander V. Chernikov } 1231ac35ff17SAlexander V. Chernikov tent->value = code; 1232ac35ff17SAlexander V. Chernikov break; 1233ac35ff17SAlexander V. Chernikov default: 1234ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 1235ac35ff17SAlexander V. Chernikov } 1236adf3b2b9SAlexander V. Chernikov #endif 1237ac35ff17SAlexander V. Chernikov } 1238f1220db8SAlexander V. Chernikov 1239f1220db8SAlexander V. Chernikov /* 1240f1220db8SAlexander V. Chernikov * Compare table names. 1241f1220db8SAlexander V. Chernikov * Honor number comparison. 1242f1220db8SAlexander V. Chernikov */ 1243f1220db8SAlexander V. Chernikov static int 1244f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 1245f1220db8SAlexander V. Chernikov { 1246f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 1247f1220db8SAlexander V. Chernikov 1248f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 1249f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 1250f1220db8SAlexander V. Chernikov 125168394ec8SAlexander V. Chernikov return (stringnum_cmp(ia->tablename, ib->tablename)); 1252f1220db8SAlexander V. Chernikov } 1253f1220db8SAlexander V. Chernikov 1254f1220db8SAlexander V. Chernikov /* 1255f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 1256f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 1257f1220db8SAlexander V. Chernikov * Returns 0 on success. 1258f1220db8SAlexander V. Chernikov */ 1259f1220db8SAlexander V. Chernikov static int 1260f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 1261f1220db8SAlexander V. Chernikov { 126228ea4fa3SAlexander V. Chernikov ipfw_obj_lheader *olh; 1263f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 1264f1220db8SAlexander V. Chernikov size_t sz; 1265f1220db8SAlexander V. Chernikov int i, error; 1266f1220db8SAlexander V. Chernikov 126728ea4fa3SAlexander V. Chernikov /* Start with reasonable default */ 126828ea4fa3SAlexander V. Chernikov sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1269f1220db8SAlexander V. Chernikov 127028ea4fa3SAlexander V. Chernikov for (;;) { 1271f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 1272f1220db8SAlexander V. Chernikov return (ENOMEM); 1273f1220db8SAlexander V. Chernikov 1274f1220db8SAlexander V. Chernikov olh->size = sz; 127528ea4fa3SAlexander V. Chernikov error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz); 127628ea4fa3SAlexander V. Chernikov if (error == ENOMEM) { 127728ea4fa3SAlexander V. Chernikov sz = olh->size; 1278f1220db8SAlexander V. Chernikov free(olh); 127928ea4fa3SAlexander V. Chernikov continue; 128028ea4fa3SAlexander V. Chernikov } else if (error != 0) { 128128ea4fa3SAlexander V. Chernikov free(olh); 128228ea4fa3SAlexander V. Chernikov return (error); 1283f1220db8SAlexander V. Chernikov } 1284f1220db8SAlexander V. Chernikov 1285f1220db8SAlexander V. Chernikov if (sort != 0) 1286f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1287f1220db8SAlexander V. Chernikov 1288f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 1289f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 1290f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 1291f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1292f1220db8SAlexander V. Chernikov } 1293f1220db8SAlexander V. Chernikov 1294f1220db8SAlexander V. Chernikov free(olh); 129528ea4fa3SAlexander V. Chernikov break; 129628ea4fa3SAlexander V. Chernikov } 1297f1220db8SAlexander V. Chernikov 1298f1220db8SAlexander V. Chernikov return (0); 1299f1220db8SAlexander V. Chernikov } 1300f1220db8SAlexander V. Chernikov 130128ea4fa3SAlexander V. Chernikov 1302f1220db8SAlexander V. Chernikov /* 1303f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 1304*720ee730SAlexander V. Chernikov * eXtended format. Allocate buffer large enough 1305*720ee730SAlexander V. Chernikov * to store result. Called needs to free it later. 1306f1220db8SAlexander V. Chernikov * 1307f1220db8SAlexander V. Chernikov * Returns 0 on success. 1308f1220db8SAlexander V. Chernikov */ 1309f1220db8SAlexander V. Chernikov static int 1310*720ee730SAlexander V. Chernikov table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1311f1220db8SAlexander V. Chernikov { 1312*720ee730SAlexander V. Chernikov ipfw_obj_header *oh; 1313f1220db8SAlexander V. Chernikov size_t sz; 131481d3153dSAlexander V. Chernikov int error, c; 1315f1220db8SAlexander V. Chernikov 131681d3153dSAlexander V. Chernikov sz = 0; 1317*720ee730SAlexander V. Chernikov oh = NULL; 1318*720ee730SAlexander V. Chernikov error = 0; 1319*720ee730SAlexander V. Chernikov for (c = 0; c < 8; c++) { 132081d3153dSAlexander V. Chernikov if (sz < i->size) 1321*720ee730SAlexander V. Chernikov sz = i->size + 44; 1322*720ee730SAlexander V. Chernikov if (oh != NULL) 1323*720ee730SAlexander V. Chernikov free(oh); 1324*720ee730SAlexander V. Chernikov if ((oh = calloc(1, sz)) == NULL) 1325*720ee730SAlexander V. Chernikov continue; 1326*720ee730SAlexander V. Chernikov table_fill_objheader(oh, i); 1327d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 132881d3153dSAlexander V. Chernikov error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz); 1329d3a4f924SAlexander V. Chernikov 1330*720ee730SAlexander V. Chernikov if (error == 0) { 1331*720ee730SAlexander V. Chernikov *poh = oh; 1332*720ee730SAlexander V. Chernikov return (0); 133381d3153dSAlexander V. Chernikov } 1334f1220db8SAlexander V. Chernikov 1335*720ee730SAlexander V. Chernikov if (error != ENOMEM) 1336*720ee730SAlexander V. Chernikov break; 1337*720ee730SAlexander V. Chernikov } 1338*720ee730SAlexander V. Chernikov free(oh); 1339*720ee730SAlexander V. Chernikov 1340*720ee730SAlexander V. Chernikov return (error); 1341f1220db8SAlexander V. Chernikov } 1342f1220db8SAlexander V. Chernikov 1343f1220db8SAlexander V. Chernikov /* 1344f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 1345f1220db8SAlexander V. Chernikov */ 1346f1220db8SAlexander V. Chernikov static void 1347f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 1348f1220db8SAlexander V. Chernikov { 134981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 135081d3153dSAlexander V. Chernikov uint32_t count; 1351f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1352f1220db8SAlexander V. Chernikov 1353f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 135481d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(i + 1); 1355f1220db8SAlexander V. Chernikov 1356f1220db8SAlexander V. Chernikov if (need_header) 1357f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1358f1220db8SAlexander V. Chernikov 1359f1220db8SAlexander V. Chernikov count = i->count; 1360f1220db8SAlexander V. Chernikov while (count > 0) { 136181d3153dSAlexander V. Chernikov table_show_entry(i, tent); 136281d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 136381d3153dSAlexander V. Chernikov count--; 136481d3153dSAlexander V. Chernikov } 136581d3153dSAlexander V. Chernikov } 136681d3153dSAlexander V. Chernikov 136781d3153dSAlexander V. Chernikov static void 136881d3153dSAlexander V. Chernikov table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 136981d3153dSAlexander V. Chernikov { 1370914bffb6SAlexander V. Chernikov char *comma, tbuf[128], pval[32]; 1371914bffb6SAlexander V. Chernikov void *paddr; 137281d3153dSAlexander V. Chernikov uint32_t tval; 1373914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 137481d3153dSAlexander V. Chernikov 137581d3153dSAlexander V. Chernikov tval = tent->value; 137681d3153dSAlexander V. Chernikov 1377adf3b2b9SAlexander V. Chernikov if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) { 1378914bffb6SAlexander V. Chernikov tval = htonl(tval); 1379914bffb6SAlexander V. Chernikov inet_ntop(AF_INET, &tval, pval, sizeof(pval)); 1380914bffb6SAlexander V. Chernikov } else 1381914bffb6SAlexander V. Chernikov snprintf(pval, sizeof(pval), "%u", tval); 1382914bffb6SAlexander V. Chernikov 1383f1220db8SAlexander V. Chernikov switch (i->type) { 1384f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 1385f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 138681d3153dSAlexander V. Chernikov inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1387914bffb6SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1388f1220db8SAlexander V. Chernikov break; 1389f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1390f1220db8SAlexander V. Chernikov /* Interface names */ 1391914bffb6SAlexander V. Chernikov printf("%s %s\n", tent->k.iface, pval); 1392b23d5de9SAlexander V. Chernikov break; 1393b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 1394b23d5de9SAlexander V. Chernikov /* numbers */ 1395914bffb6SAlexander V. Chernikov printf("%u %s\n", tent->k.key, pval); 1396b23d5de9SAlexander V. Chernikov break; 1397914bffb6SAlexander V. Chernikov case IPFW_TABLE_FLOW: 1398914bffb6SAlexander V. Chernikov /* flows */ 1399914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 1400914bffb6SAlexander V. Chernikov comma = ""; 1401914bffb6SAlexander V. Chernikov 1402914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1403914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1404914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.sip; 1405914bffb6SAlexander V. Chernikov else 1406914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.sip6; 1407914bffb6SAlexander V. Chernikov 1408914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1409914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1410914bffb6SAlexander V. Chernikov comma = ","; 1411914bffb6SAlexander V. Chernikov } 1412914bffb6SAlexander V. Chernikov 1413914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1414914bffb6SAlexander V. Chernikov printf("%s%d", comma, tfe->proto); 1415914bffb6SAlexander V. Chernikov comma = ","; 1416914bffb6SAlexander V. Chernikov } 1417914bffb6SAlexander V. Chernikov 1418914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1419914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->sport)); 1420914bffb6SAlexander V. Chernikov comma = ","; 1421914bffb6SAlexander V. Chernikov } 1422914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1423914bffb6SAlexander V. Chernikov if (tfe->af == AF_INET) 1424914bffb6SAlexander V. Chernikov paddr = &tfe->a.a4.dip; 1425914bffb6SAlexander V. Chernikov else 1426914bffb6SAlexander V. Chernikov paddr = &tfe->a.a6.dip6; 1427914bffb6SAlexander V. Chernikov 1428914bffb6SAlexander V. Chernikov inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1429914bffb6SAlexander V. Chernikov printf("%s%s", comma, tbuf); 1430914bffb6SAlexander V. Chernikov comma = ","; 1431914bffb6SAlexander V. Chernikov } 1432914bffb6SAlexander V. Chernikov 1433914bffb6SAlexander V. Chernikov if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1434914bffb6SAlexander V. Chernikov printf("%s%d", comma, ntohs(tfe->dport)); 1435914bffb6SAlexander V. Chernikov comma = ","; 1436914bffb6SAlexander V. Chernikov } 1437914bffb6SAlexander V. Chernikov 1438914bffb6SAlexander V. Chernikov printf(" %s\n", pval); 1439f1220db8SAlexander V. Chernikov } 1440f1220db8SAlexander V. Chernikov } 1441f1220db8SAlexander V. Chernikov 14429d099b4fSAlexander V. Chernikov static int 14439d099b4fSAlexander V. Chernikov table_do_get_algolist(ipfw_obj_lheader **polh) 14449d099b4fSAlexander V. Chernikov { 14459d099b4fSAlexander V. Chernikov ipfw_obj_lheader req, *olh; 14469d099b4fSAlexander V. Chernikov size_t sz; 14479d099b4fSAlexander V. Chernikov int error; 14489d099b4fSAlexander V. Chernikov 14499d099b4fSAlexander V. Chernikov memset(&req, 0, sizeof(req)); 14509d099b4fSAlexander V. Chernikov sz = sizeof(req); 14519d099b4fSAlexander V. Chernikov 14529d099b4fSAlexander V. Chernikov error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); 14539d099b4fSAlexander V. Chernikov if (error != 0 && error != ENOMEM) 14549d099b4fSAlexander V. Chernikov return (error); 14559d099b4fSAlexander V. Chernikov 14569d099b4fSAlexander V. Chernikov sz = req.size; 14579d099b4fSAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 14589d099b4fSAlexander V. Chernikov return (ENOMEM); 14599d099b4fSAlexander V. Chernikov 14609d099b4fSAlexander V. Chernikov olh->size = sz; 14619d099b4fSAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { 14629d099b4fSAlexander V. Chernikov free(olh); 14639d099b4fSAlexander V. Chernikov return (error); 14649d099b4fSAlexander V. Chernikov } 14659d099b4fSAlexander V. Chernikov 14669d099b4fSAlexander V. Chernikov *polh = olh; 14679d099b4fSAlexander V. Chernikov return (0); 14689d099b4fSAlexander V. Chernikov } 14699d099b4fSAlexander V. Chernikov 14709d099b4fSAlexander V. Chernikov void 14719d099b4fSAlexander V. Chernikov ipfw_list_ta(int ac, char *av[]) 14729d099b4fSAlexander V. Chernikov { 14739d099b4fSAlexander V. Chernikov ipfw_obj_lheader *olh; 14749d099b4fSAlexander V. Chernikov ipfw_ta_info *info; 14759d099b4fSAlexander V. Chernikov int error, i; 14769d099b4fSAlexander V. Chernikov const char *atype; 14779d099b4fSAlexander V. Chernikov 14789d099b4fSAlexander V. Chernikov error = table_do_get_algolist(&olh); 14799d099b4fSAlexander V. Chernikov if (error != 0) 14809d099b4fSAlexander V. Chernikov err(EX_OSERR, "Unable to request algorithm list"); 14819d099b4fSAlexander V. Chernikov 14829d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)(olh + 1); 14839d099b4fSAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 14849d099b4fSAlexander V. Chernikov if ((atype = match_value(tabletypes, info->type)) == NULL) 14859d099b4fSAlexander V. Chernikov atype = "unknown"; 14868ce7a2bcSAlexander V. Chernikov printf("--- %s ---\n", info->algoname); 14878ce7a2bcSAlexander V. Chernikov printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 14889d099b4fSAlexander V. Chernikov 14899d099b4fSAlexander V. Chernikov info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 14909d099b4fSAlexander V. Chernikov } 14919d099b4fSAlexander V. Chernikov 14929d099b4fSAlexander V. Chernikov free(olh); 14939d099b4fSAlexander V. Chernikov } 14949d099b4fSAlexander V. Chernikov 14956c2997ffSAlexander V. Chernikov int 14966c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 14976c2997ffSAlexander V. Chernikov { 14986c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 14996c2997ffSAlexander V. Chernikov 15006c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 15016c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 15026c2997ffSAlexander V. Chernikov 15036c2997ffSAlexander V. Chernikov if (a->set < b->set) 15046c2997ffSAlexander V. Chernikov return (-1); 15056c2997ffSAlexander V. Chernikov else if (a->set > b->set) 15066c2997ffSAlexander V. Chernikov return (1); 15076c2997ffSAlexander V. Chernikov 15086c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 15096c2997ffSAlexander V. Chernikov return (-1); 15106c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 15116c2997ffSAlexander V. Chernikov return (1); 15126c2997ffSAlexander V. Chernikov 15136c2997ffSAlexander V. Chernikov return (0); 15146c2997ffSAlexander V. Chernikov } 1515563b5ab1SAlexander V. Chernikov 1516563b5ab1SAlexander V. Chernikov int 15176c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 1518563b5ab1SAlexander V. Chernikov { 1519563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1520563b5ab1SAlexander V. Chernikov uint16_t key; 1521563b5ab1SAlexander V. Chernikov 1522563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 1523563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 1524563b5ab1SAlexander V. Chernikov 1525563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 1526563b5ab1SAlexander V. Chernikov return (-1); 1527563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 1528563b5ab1SAlexander V. Chernikov return (1); 1529563b5ab1SAlexander V. Chernikov 1530563b5ab1SAlexander V. Chernikov return (0); 1531563b5ab1SAlexander V. Chernikov } 1532563b5ab1SAlexander V. Chernikov 1533563b5ab1SAlexander V. Chernikov /* 1534563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 1535563b5ab1SAlexander V. Chernikov * Uses the following facts: 1536563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 1537563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 1538563b5ab1SAlexander V. Chernikov * 1539563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 1540563b5ab1SAlexander V. Chernikov */ 1541563b5ab1SAlexander V. Chernikov char * 1542563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 1543563b5ab1SAlexander V. Chernikov { 1544563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1545563b5ab1SAlexander V. Chernikov 1546563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 15476c2997ffSAlexander V. Chernikov compare_kntlv); 1548563b5ab1SAlexander V. Chernikov 1549563b5ab1SAlexander V. Chernikov if (ntlv != 0) 1550563b5ab1SAlexander V. Chernikov return (ntlv->name); 1551563b5ab1SAlexander V. Chernikov 1552563b5ab1SAlexander V. Chernikov return (NULL); 1553563b5ab1SAlexander V. Chernikov } 1554563b5ab1SAlexander V. Chernikov 15556c2997ffSAlexander V. Chernikov void 15566c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 15576c2997ffSAlexander V. Chernikov { 15586c2997ffSAlexander V. Chernikov 15596c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 15606c2997ffSAlexander V. Chernikov } 15616c2997ffSAlexander V. Chernikov 15626c2997ffSAlexander V. Chernikov int 15636c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 15646c2997ffSAlexander V. Chernikov { 15656c2997ffSAlexander V. Chernikov int c, i, l; 15666c2997ffSAlexander V. Chernikov 15676c2997ffSAlexander V. Chernikov /* 15686c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 15696c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 1570ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 15716c2997ffSAlexander V. Chernikov */ 15726c2997ffSAlexander V. Chernikov l = strlen(tablename); 15736c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 15746c2997ffSAlexander V. Chernikov return (EINVAL); 15756c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 15766c2997ffSAlexander V. Chernikov c = tablename[i]; 15776c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 15786c2997ffSAlexander V. Chernikov c == '-' || c == '.') 15796c2997ffSAlexander V. Chernikov continue; 15806c2997ffSAlexander V. Chernikov return (EINVAL); 15816c2997ffSAlexander V. Chernikov } 15826c2997ffSAlexander V. Chernikov 1583ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 1584ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 1585ac35ff17SAlexander V. Chernikov return (EINVAL); 1586ac35ff17SAlexander V. Chernikov 15876c2997ffSAlexander V. Chernikov return (0); 15886c2997ffSAlexander V. Chernikov } 15896c2997ffSAlexander V. Chernikov 1590