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); 52*ac35ff17SAlexander V. Chernikov static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 53*ac35ff17SAlexander V. Chernikov int add, int update); 54*ac35ff17SAlexander V. Chernikov static int table_flush(ipfw_obj_header *oh); 55*ac35ff17SAlexander V. Chernikov static int table_destroy(ipfw_obj_header *oh); 56*ac35ff17SAlexander V. Chernikov static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 57*ac35ff17SAlexander V. Chernikov static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 58*ac35ff17SAlexander V. Chernikov static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 59f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 60*ac35ff17SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, 61*ac35ff17SAlexander V. Chernikov uint16_t uidx); 62f1220db8SAlexander V. Chernikov 63f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 64f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 65f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh); 66f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 67f1220db8SAlexander V. Chernikov 68*ac35ff17SAlexander V. Chernikov static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 69*ac35ff17SAlexander V. Chernikov char *key, uint8_t *ptype, uint8_t *pvtype); 70*ac35ff17SAlexander V. Chernikov static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 71*ac35ff17SAlexander V. Chernikov char *arg, uint8_t type, uint8_t vtype); 72*ac35ff17SAlexander V. Chernikov 73f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 74f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 75f1220db8SAlexander V. Chernikov 76f1220db8SAlexander V. Chernikov #ifndef s6_addr32 77f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 78f1220db8SAlexander V. Chernikov #endif 79f1220db8SAlexander V. Chernikov 80*ac35ff17SAlexander V. Chernikov static struct _s_x tabletypes[] = { 81*ac35ff17SAlexander V. Chernikov { "cidr", IPFW_TABLE_CIDR }, 82*ac35ff17SAlexander V. Chernikov { "iface", IPFW_TABLE_INTERFACE }, 83*ac35ff17SAlexander V. Chernikov { "u32", IPFW_TABLE_U32 }, 84*ac35ff17SAlexander V. Chernikov { NULL, 0 } 85*ac35ff17SAlexander V. Chernikov }; 86*ac35ff17SAlexander V. Chernikov 87*ac35ff17SAlexander V. Chernikov static struct _s_x tablevaltypes[] = { 88*ac35ff17SAlexander V. Chernikov { "dscp", IPFW_VTYPE_DSCP }, 89*ac35ff17SAlexander V. Chernikov { "ip", IPFW_VTYPE_IP }, 90*ac35ff17SAlexander V. Chernikov { "number", IPFW_VTYPE_U32 }, 91*ac35ff17SAlexander V. Chernikov { NULL, 0 } 92*ac35ff17SAlexander V. Chernikov }; 93*ac35ff17SAlexander V. Chernikov 94*ac35ff17SAlexander V. Chernikov static struct _s_x tablecmds[] = { 95*ac35ff17SAlexander V. Chernikov { "add", TOK_ADD }, 96*ac35ff17SAlexander V. Chernikov { "create", TOK_CREATE }, 97*ac35ff17SAlexander V. Chernikov { "delete", TOK_DEL }, 98*ac35ff17SAlexander V. Chernikov { "destroy", TOK_DESTROY }, 99*ac35ff17SAlexander V. Chernikov { "flush", TOK_FLUSH }, 100*ac35ff17SAlexander V. Chernikov { "info", TOK_INFO }, 101*ac35ff17SAlexander V. Chernikov { "list", TOK_LIST }, 102*ac35ff17SAlexander V. Chernikov { NULL, 0 } 103*ac35ff17SAlexander V. Chernikov }; 104*ac35ff17SAlexander V. Chernikov 105f1220db8SAlexander V. Chernikov static int 106f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 107f1220db8SAlexander V. Chernikov { 108f1220db8SAlexander V. Chernikov struct hostent *he; 109f1220db8SAlexander V. Chernikov 110f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 111f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 112f1220db8SAlexander V. Chernikov return(-1); 113f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 114f1220db8SAlexander V. Chernikov } 115f1220db8SAlexander V. Chernikov return(0); 116f1220db8SAlexander V. Chernikov } 117f1220db8SAlexander V. Chernikov 118f1220db8SAlexander V. Chernikov /* 119f1220db8SAlexander V. Chernikov * This one handles all table-related commands 120*ac35ff17SAlexander V. Chernikov * ipfw table NAME create ... 121*ac35ff17SAlexander V. Chernikov * ipfw table NAME destroy 122*ac35ff17SAlexander V. Chernikov * ipfw table NAME add addr[/masklen] [value] 123*ac35ff17SAlexander V. Chernikov * ipfw table NAME delete addr[/masklen] 124*ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} flush 125*ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} list 126*ac35ff17SAlexander V. Chernikov * ipfw table {NAME | all} info 127f1220db8SAlexander V. Chernikov */ 128f1220db8SAlexander V. Chernikov void 129f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 130f1220db8SAlexander V. Chernikov { 131*ac35ff17SAlexander V. Chernikov int do_add, is_all; 132*ac35ff17SAlexander V. Chernikov int error, tcmd; 133*ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 134*ac35ff17SAlexander V. Chernikov ipfw_obj_header oh; 135f1220db8SAlexander V. Chernikov char *tablename; 136*ac35ff17SAlexander V. Chernikov uint32_t set; 137f1220db8SAlexander V. Chernikov 138*ac35ff17SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 139*ac35ff17SAlexander V. Chernikov is_all = 0; 140*ac35ff17SAlexander V. Chernikov if (co.use_set != 0) 141*ac35ff17SAlexander V. Chernikov set = co.use_set - 1; 142*ac35ff17SAlexander V. Chernikov else 143*ac35ff17SAlexander V. Chernikov set = 0; 144f1220db8SAlexander V. Chernikov 145f1220db8SAlexander V. Chernikov ac--; av++; 146f1220db8SAlexander V. Chernikov tablename = *av; 147f1220db8SAlexander V. Chernikov 148*ac35ff17SAlexander V. Chernikov if (table_check_name(tablename) == 0) { 149*ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, *av, set, 1); 150*ac35ff17SAlexander V. Chernikov //oh->set = set; 151*ac35ff17SAlexander V. Chernikov oh.idx = 1; 152*ac35ff17SAlexander V. Chernikov } else { 153*ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 154*ac35ff17SAlexander V. Chernikov is_all = 1; 155*ac35ff17SAlexander V. Chernikov else 156*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name %s is invalid", tablename); 157*ac35ff17SAlexander V. Chernikov } 158*ac35ff17SAlexander V. Chernikov ac--; av++; 159*ac35ff17SAlexander V. Chernikov 160*ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablecmds, *av)) == -1) 161*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 162*ac35ff17SAlexander V. Chernikov 163*ac35ff17SAlexander V. Chernikov NEED1("table needs command"); 164*ac35ff17SAlexander V. Chernikov switch (tcmd) { 165*ac35ff17SAlexander V. Chernikov case TOK_LIST: 166*ac35ff17SAlexander V. Chernikov case TOK_INFO: 167*ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 168*ac35ff17SAlexander V. Chernikov break; 169*ac35ff17SAlexander V. Chernikov default: 170*ac35ff17SAlexander V. Chernikov if (is_all != 0) 171*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "table name required"); 172*ac35ff17SAlexander V. Chernikov } 173*ac35ff17SAlexander V. Chernikov 174*ac35ff17SAlexander V. Chernikov switch (tcmd) { 175*ac35ff17SAlexander V. Chernikov case TOK_ADD: 176*ac35ff17SAlexander V. Chernikov case TOK_DEL: 177f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 178f1220db8SAlexander V. Chernikov ac--; av++; 179*ac35ff17SAlexander V. Chernikov table_modify_record(&oh, ac, av, do_add, co.do_quiet); 180*ac35ff17SAlexander V. Chernikov break; 181*ac35ff17SAlexander V. Chernikov case TOK_CREATE: 182f1220db8SAlexander V. Chernikov ac--; av++; 183*ac35ff17SAlexander V. Chernikov table_create(&oh, ac, av); 184*ac35ff17SAlexander V. Chernikov break; 185*ac35ff17SAlexander V. Chernikov case TOK_DESTROY: 186*ac35ff17SAlexander V. Chernikov if (table_destroy(&oh) != 0) 187*ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 188*ac35ff17SAlexander V. Chernikov break; 189*ac35ff17SAlexander V. Chernikov case TOK_FLUSH: 190f1220db8SAlexander V. Chernikov if (is_all == 0) { 191*ac35ff17SAlexander V. Chernikov if ((error = table_flush(&oh)) != 0) 192f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 193f1220db8SAlexander V. Chernikov tablename); 194f1220db8SAlexander V. Chernikov } else { 195*ac35ff17SAlexander V. Chernikov error = tables_foreach(table_flush_one, &oh, 1); 196f1220db8SAlexander V. Chernikov if (error != 0) 197f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 198f1220db8SAlexander V. Chernikov } 199*ac35ff17SAlexander V. Chernikov break; 200*ac35ff17SAlexander V. Chernikov case TOK_INFO: 201f1220db8SAlexander V. Chernikov if (is_all == 0) { 202*ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 203f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 204f1220db8SAlexander V. Chernikov table_show_info(&i, NULL); 205f1220db8SAlexander V. Chernikov } else { 206f1220db8SAlexander V. Chernikov error = tables_foreach(table_show_info, NULL, 1); 207f1220db8SAlexander V. Chernikov if (error != 0) 208f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 209f1220db8SAlexander V. Chernikov } 210*ac35ff17SAlexander V. Chernikov break; 211*ac35ff17SAlexander V. Chernikov case TOK_LIST: 212*ac35ff17SAlexander V. Chernikov if (is_all == 0) { 213*ac35ff17SAlexander V. Chernikov ipfw_xtable_info i; 214*ac35ff17SAlexander V. Chernikov if ((error = table_get_info(&oh, &i)) != 0) 215*ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 216*ac35ff17SAlexander V. Chernikov table_show_one(&i, NULL); 217f1220db8SAlexander V. Chernikov } else { 218*ac35ff17SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 219*ac35ff17SAlexander V. Chernikov if (error != 0) 220*ac35ff17SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 221f1220db8SAlexander V. Chernikov } 222*ac35ff17SAlexander V. Chernikov break; 223f1220db8SAlexander V. Chernikov } 224f1220db8SAlexander V. Chernikov } 225f1220db8SAlexander V. Chernikov 226f1220db8SAlexander V. Chernikov static void 227*ac35ff17SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx) 228f1220db8SAlexander V. Chernikov { 229f1220db8SAlexander V. Chernikov 230563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 231f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 232f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 233*ac35ff17SAlexander V. Chernikov ntlv->set = set; 234f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 235f1220db8SAlexander V. Chernikov } 236f1220db8SAlexander V. Chernikov 237f1220db8SAlexander V. Chernikov static void 238f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 239f1220db8SAlexander V. Chernikov { 240f1220db8SAlexander V. Chernikov 241f1220db8SAlexander V. Chernikov oh->set = i->set; 242f1220db8SAlexander V. Chernikov oh->idx = 1; 243*ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, oh->set, 1); 244*ac35ff17SAlexander V. Chernikov } 245*ac35ff17SAlexander V. Chernikov 246*ac35ff17SAlexander V. Chernikov static struct _s_x tablenewcmds[] = { 247*ac35ff17SAlexander V. Chernikov { "type", TOK_TYPE}, 248*ac35ff17SAlexander V. Chernikov { "valtype", TOK_VALTYPE }, 249*ac35ff17SAlexander V. Chernikov { "algo", TOK_ALGO }, 250*ac35ff17SAlexander V. Chernikov { NULL, 0 } 251*ac35ff17SAlexander V. Chernikov }; 252*ac35ff17SAlexander V. Chernikov 253*ac35ff17SAlexander V. Chernikov /* 254*ac35ff17SAlexander V. Chernikov * Creates new table 255*ac35ff17SAlexander V. Chernikov * 256*ac35ff17SAlexander V. Chernikov * ipfw table NAME create [ type { cidr | iface | u32 } ] 257*ac35ff17SAlexander V. Chernikov * [ valtype { number | ip | dscp } ] 258*ac35ff17SAlexander V. Chernikov * [ algo algoname ] 259*ac35ff17SAlexander V. Chernikov * 260*ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 261*ac35ff17SAlexander V. Chernikov */ 262*ac35ff17SAlexander V. Chernikov static void 263*ac35ff17SAlexander V. Chernikov table_create(ipfw_obj_header *oh, int ac, char *av[]) 264*ac35ff17SAlexander V. Chernikov { 265*ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 266*ac35ff17SAlexander V. Chernikov int error, tcmd, val; 267*ac35ff17SAlexander V. Chernikov size_t sz; 268*ac35ff17SAlexander V. Chernikov char tbuf[128]; 269*ac35ff17SAlexander V. Chernikov 270*ac35ff17SAlexander V. Chernikov sz = sizeof(tbuf); 271*ac35ff17SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 272*ac35ff17SAlexander V. Chernikov 273*ac35ff17SAlexander V. Chernikov /* Set some defaults to preserve compability */ 274*ac35ff17SAlexander V. Chernikov xi.type = IPFW_TABLE_CIDR; 275*ac35ff17SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 276*ac35ff17SAlexander V. Chernikov 277*ac35ff17SAlexander V. Chernikov while (ac > 0) { 278*ac35ff17SAlexander V. Chernikov if ((tcmd = match_token(tablenewcmds, *av)) == -1) 279*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "unknown option: %s", *av); 280*ac35ff17SAlexander V. Chernikov ac--; av++; 281*ac35ff17SAlexander V. Chernikov 282*ac35ff17SAlexander V. Chernikov switch (tcmd) { 283*ac35ff17SAlexander V. Chernikov case TOK_TYPE: 284*ac35ff17SAlexander V. Chernikov NEED1("table type required"); 285*ac35ff17SAlexander V. Chernikov val = match_token(tabletypes, *av); 286*ac35ff17SAlexander V. Chernikov if (val != -1) { 287*ac35ff17SAlexander V. Chernikov printf("av %s type %d\n", *av, xi.type); 288*ac35ff17SAlexander V. Chernikov xi.type = val; 289*ac35ff17SAlexander V. Chernikov ac--; av++; 290*ac35ff17SAlexander V. Chernikov break; 291*ac35ff17SAlexander V. Chernikov } 292*ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tabletypes, ", "); 293*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown tabletype: %s. Supported: %s", 294*ac35ff17SAlexander V. Chernikov *av, tbuf); 295*ac35ff17SAlexander V. Chernikov break; 296*ac35ff17SAlexander V. Chernikov case TOK_VALTYPE: 297*ac35ff17SAlexander V. Chernikov NEED1("table value type required"); 298*ac35ff17SAlexander V. Chernikov val = match_token(tablevaltypes, *av); 299*ac35ff17SAlexander V. Chernikov if (val != -1) { 300*ac35ff17SAlexander V. Chernikov xi.vtype = val; 301*ac35ff17SAlexander V. Chernikov ac--; av++; 302*ac35ff17SAlexander V. Chernikov break; 303*ac35ff17SAlexander V. Chernikov } 304*ac35ff17SAlexander V. Chernikov concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 305*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 306*ac35ff17SAlexander V. Chernikov *av, tbuf); 307*ac35ff17SAlexander V. Chernikov break; 308*ac35ff17SAlexander V. Chernikov case TOK_ALGO: 309*ac35ff17SAlexander V. Chernikov NEED1("table algorithm name required"); 310*ac35ff17SAlexander V. Chernikov if (strlen(*av) > sizeof(xi.algoname)) 311*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "algorithm name too long"); 312*ac35ff17SAlexander V. Chernikov strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 313*ac35ff17SAlexander V. Chernikov ac--; av++; 314*ac35ff17SAlexander V. Chernikov break; 315*ac35ff17SAlexander V. Chernikov } 316*ac35ff17SAlexander V. Chernikov } 317*ac35ff17SAlexander V. Chernikov 318*ac35ff17SAlexander V. Chernikov if ((error = table_do_create(oh, &xi)) != 0) 319*ac35ff17SAlexander V. Chernikov err(EX_OSERR, "Table creation failed"); 320f1220db8SAlexander V. Chernikov } 321f1220db8SAlexander V. Chernikov 322f1220db8SAlexander V. Chernikov /* 323*ac35ff17SAlexander V. Chernikov * Creates new table 324*ac35ff17SAlexander V. Chernikov * 325*ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 326*ac35ff17SAlexander V. Chernikov * 327f1220db8SAlexander V. Chernikov * Returns 0 on success. 328f1220db8SAlexander V. Chernikov */ 329f1220db8SAlexander V. Chernikov static int 330*ac35ff17SAlexander V. Chernikov table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 331f1220db8SAlexander V. Chernikov { 332*ac35ff17SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 333*ac35ff17SAlexander V. Chernikov int error; 334f1220db8SAlexander V. Chernikov 335*ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 336*ac35ff17SAlexander V. Chernikov memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 337*ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 338*ac35ff17SAlexander V. Chernikov 339*ac35ff17SAlexander V. Chernikov error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 340*ac35ff17SAlexander V. Chernikov 341*ac35ff17SAlexander V. Chernikov return (error); 342*ac35ff17SAlexander V. Chernikov } 343*ac35ff17SAlexander V. Chernikov 344*ac35ff17SAlexander V. Chernikov /* 345*ac35ff17SAlexander V. Chernikov * Destroys given table specified by @oh->ntlv. 346*ac35ff17SAlexander V. Chernikov * Returns 0 on success. 347*ac35ff17SAlexander V. Chernikov */ 348*ac35ff17SAlexander V. Chernikov static int 349*ac35ff17SAlexander V. Chernikov table_destroy(ipfw_obj_header *oh) 350*ac35ff17SAlexander V. Chernikov { 351*ac35ff17SAlexander V. Chernikov 352*ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 353f1220db8SAlexander V. Chernikov return (-1); 354f1220db8SAlexander V. Chernikov 355f1220db8SAlexander V. Chernikov return (0); 356f1220db8SAlexander V. Chernikov } 357f1220db8SAlexander V. Chernikov 358f1220db8SAlexander V. Chernikov /* 359*ac35ff17SAlexander V. Chernikov * Flushes given table specified by @oh->ntlv. 360f1220db8SAlexander V. Chernikov * Returns 0 on success. 361f1220db8SAlexander V. Chernikov */ 362f1220db8SAlexander V. Chernikov static int 363*ac35ff17SAlexander V. Chernikov table_flush(ipfw_obj_header *oh) 364f1220db8SAlexander V. Chernikov { 365f1220db8SAlexander V. Chernikov 366*ac35ff17SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 367f1220db8SAlexander V. Chernikov return (-1); 368f1220db8SAlexander V. Chernikov 369f1220db8SAlexander V. Chernikov return (0); 370f1220db8SAlexander V. Chernikov } 371f1220db8SAlexander V. Chernikov 372f1220db8SAlexander V. Chernikov /* 373*ac35ff17SAlexander V. Chernikov * Retrieves table in given table specified by @oh->ntlv. 374f1220db8SAlexander V. Chernikov * it inside @i. 375f1220db8SAlexander V. Chernikov * Returns 0 on success. 376f1220db8SAlexander V. Chernikov */ 377f1220db8SAlexander V. Chernikov static int 378*ac35ff17SAlexander V. Chernikov table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 379f1220db8SAlexander V. Chernikov { 380f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 381*ac35ff17SAlexander V. Chernikov int error; 382f1220db8SAlexander V. Chernikov size_t sz; 383f1220db8SAlexander V. Chernikov 384f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 385f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 386*ac35ff17SAlexander V. Chernikov memcpy(tbuf, oh, sizeof(*oh)); 387f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 388f1220db8SAlexander V. Chernikov 389*ac35ff17SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz)) != 0) 390*ac35ff17SAlexander V. Chernikov return (error); 391f1220db8SAlexander V. Chernikov 392f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 393*ac35ff17SAlexander V. Chernikov return (EINVAL); 394f1220db8SAlexander V. Chernikov 395f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 396f1220db8SAlexander V. Chernikov 397f1220db8SAlexander V. Chernikov return (0); 398f1220db8SAlexander V. Chernikov } 399f1220db8SAlexander V. Chernikov 400f1220db8SAlexander V. Chernikov /* 401f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 402f1220db8SAlexander V. Chernikov */ 403f1220db8SAlexander V. Chernikov static int 404f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 405f1220db8SAlexander V. Chernikov { 406*ac35ff17SAlexander V. Chernikov const char *ttype, *vtype; 407f1220db8SAlexander V. Chernikov 408f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 409*ac35ff17SAlexander V. Chernikov if ((ttype = match_value(tabletypes, i->type)) == NULL) 410*ac35ff17SAlexander V. Chernikov ttype = "unknown"; 411*ac35ff17SAlexander V. Chernikov if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) 412*ac35ff17SAlexander V. Chernikov vtype = "unknown"; 413*ac35ff17SAlexander V. Chernikov 414*ac35ff17SAlexander V. Chernikov printf(" type: %s, kindex: %d\n", ttype, i->kidx); 415*ac35ff17SAlexander V. Chernikov printf(" valtype: %s, algorithm: %s\n", vtype, i->algoname); 416f1220db8SAlexander V. Chernikov printf(" references: %u\n", i->refcnt); 417f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 418f1220db8SAlexander V. Chernikov 419f1220db8SAlexander V. Chernikov return (0); 420f1220db8SAlexander V. Chernikov } 421f1220db8SAlexander V. Chernikov 422f1220db8SAlexander V. Chernikov 423f1220db8SAlexander V. Chernikov /* 424f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 425f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 426f1220db8SAlexander V. Chernikov */ 427f1220db8SAlexander V. Chernikov 428f1220db8SAlexander V. Chernikov static int 429f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 430f1220db8SAlexander V. Chernikov { 431f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 432f1220db8SAlexander V. Chernikov 433*ac35ff17SAlexander V. Chernikov if ((oh = calloc(1, i->size)) == NULL) 434f1220db8SAlexander V. Chernikov return (ENOMEM); 435f1220db8SAlexander V. Chernikov 436f1220db8SAlexander V. Chernikov if (table_get_list(i, oh) == 0) 437f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 438f1220db8SAlexander V. Chernikov 439f1220db8SAlexander V. Chernikov free(oh); 440f1220db8SAlexander V. Chernikov return (0); 441f1220db8SAlexander V. Chernikov } 442f1220db8SAlexander V. Chernikov 443f1220db8SAlexander V. Chernikov static int 444f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 445f1220db8SAlexander V. Chernikov { 446*ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 447f1220db8SAlexander V. Chernikov 448*ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)arg; 449*ac35ff17SAlexander V. Chernikov 450*ac35ff17SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 451*ac35ff17SAlexander V. Chernikov 452*ac35ff17SAlexander V. Chernikov return (table_flush(oh)); 453f1220db8SAlexander V. Chernikov } 454f1220db8SAlexander V. Chernikov 455*ac35ff17SAlexander V. Chernikov static int 456*ac35ff17SAlexander V. Chernikov table_do_modify_record(int cmd, ipfw_obj_header *oh, 457*ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent, int update) 458*ac35ff17SAlexander V. Chernikov { 459*ac35ff17SAlexander V. Chernikov char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 460*ac35ff17SAlexander V. Chernikov int error; 461*ac35ff17SAlexander V. Chernikov 462*ac35ff17SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 463*ac35ff17SAlexander V. Chernikov memcpy(xbuf, oh, sizeof(*oh)); 464*ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)xbuf; 465*ac35ff17SAlexander V. Chernikov oh->opheader.version = 1; 466*ac35ff17SAlexander V. Chernikov 467*ac35ff17SAlexander V. Chernikov memcpy(oh + 1, tent, sizeof(*tent)); 468*ac35ff17SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 469*ac35ff17SAlexander V. Chernikov if (update != 0) 470*ac35ff17SAlexander V. Chernikov tent->flags |= IPFW_TF_UPDATE; 471*ac35ff17SAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 472*ac35ff17SAlexander V. Chernikov 473*ac35ff17SAlexander V. Chernikov error = do_set3(cmd, &oh->opheader, sizeof(xbuf)); 474*ac35ff17SAlexander V. Chernikov 475*ac35ff17SAlexander V. Chernikov return (error); 476*ac35ff17SAlexander V. Chernikov } 477*ac35ff17SAlexander V. Chernikov 478*ac35ff17SAlexander V. Chernikov static void 479*ac35ff17SAlexander V. Chernikov table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, int update) 480*ac35ff17SAlexander V. Chernikov { 481*ac35ff17SAlexander V. Chernikov ipfw_obj_tentry tent; 482*ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 483*ac35ff17SAlexander V. Chernikov int cmd; 484*ac35ff17SAlexander V. Chernikov char *texterr; 485*ac35ff17SAlexander V. Chernikov 486*ac35ff17SAlexander V. Chernikov if (ac == 0) 487*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "address required"); 488*ac35ff17SAlexander V. Chernikov 489*ac35ff17SAlexander V. Chernikov memset(&tent, 0, sizeof(tent)); 490*ac35ff17SAlexander V. Chernikov tent.head.length = sizeof(tent); 491*ac35ff17SAlexander V. Chernikov tent.idx = 1; 492*ac35ff17SAlexander V. Chernikov 493*ac35ff17SAlexander V. Chernikov tentry_fill_key(oh, &tent, *av, &type, &vtype); 494*ac35ff17SAlexander V. Chernikov oh->ntlv.type = type; 495*ac35ff17SAlexander V. Chernikov ac--; av++; 496*ac35ff17SAlexander V. Chernikov 497*ac35ff17SAlexander V. Chernikov if (add != 0) { 498*ac35ff17SAlexander V. Chernikov if (ac > 0) 499*ac35ff17SAlexander V. Chernikov tentry_fill_value(oh, &tent, *av, type, vtype); 500*ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XADD; 501*ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XADD)"; 502*ac35ff17SAlexander V. Chernikov } else { 503*ac35ff17SAlexander V. Chernikov cmd = IP_FW_TABLE_XDEL; 504*ac35ff17SAlexander V. Chernikov texterr = "setsockopt(IP_FW_TABLE_XDEL)"; 505*ac35ff17SAlexander V. Chernikov } 506*ac35ff17SAlexander V. Chernikov 507*ac35ff17SAlexander V. Chernikov if (table_do_modify_record(cmd, oh, &tent, update) != 0) 508*ac35ff17SAlexander V. Chernikov err(EX_OSERR, "%s", texterr); 509*ac35ff17SAlexander V. Chernikov } 510*ac35ff17SAlexander V. Chernikov 511*ac35ff17SAlexander V. Chernikov 512*ac35ff17SAlexander V. Chernikov static void 513*ac35ff17SAlexander V. Chernikov tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type) 514*ac35ff17SAlexander V. Chernikov { 515*ac35ff17SAlexander V. Chernikov char *p; 516*ac35ff17SAlexander V. Chernikov int mask, af; 517*ac35ff17SAlexander V. Chernikov struct in6_addr *paddr; 518*ac35ff17SAlexander V. Chernikov uint32_t key, *pkey; 519*ac35ff17SAlexander V. Chernikov int masklen; 520*ac35ff17SAlexander V. Chernikov 521*ac35ff17SAlexander V. Chernikov masklen = 0; 522*ac35ff17SAlexander V. Chernikov af = 0; 523*ac35ff17SAlexander V. Chernikov paddr = (struct in6_addr *)&tentry->k; 524*ac35ff17SAlexander V. Chernikov 525*ac35ff17SAlexander V. Chernikov switch (type) { 526*ac35ff17SAlexander V. Chernikov case IPFW_TABLE_CIDR: 527*ac35ff17SAlexander V. Chernikov /* Remove / if exists */ 528*ac35ff17SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 529*ac35ff17SAlexander V. Chernikov *p = '\0'; 530*ac35ff17SAlexander V. Chernikov mask = atoi(p + 1); 531*ac35ff17SAlexander V. Chernikov } 532*ac35ff17SAlexander V. Chernikov 533*ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 534*ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 32) 535*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 536*ac35ff17SAlexander V. Chernikov p + 1); 537*ac35ff17SAlexander V. Chernikov 538*ac35ff17SAlexander V. Chernikov masklen = p ? mask : 32; 539*ac35ff17SAlexander V. Chernikov af = AF_INET; 540*ac35ff17SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 541*ac35ff17SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 542*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, 543*ac35ff17SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 544*ac35ff17SAlexander V. Chernikov if (p != NULL && mask > 128) 545*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 546*ac35ff17SAlexander V. Chernikov p + 1); 547*ac35ff17SAlexander V. Chernikov 548*ac35ff17SAlexander V. Chernikov masklen = p ? mask : 128; 549*ac35ff17SAlexander V. Chernikov af = AF_INET6; 550*ac35ff17SAlexander V. Chernikov } else { 551*ac35ff17SAlexander V. Chernikov /* Assume FQDN */ 552*ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 553*ac35ff17SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 554*ac35ff17SAlexander V. Chernikov 555*ac35ff17SAlexander V. Chernikov masklen = 32; 556*ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 557*ac35ff17SAlexander V. Chernikov af = AF_INET; 558*ac35ff17SAlexander V. Chernikov } 559*ac35ff17SAlexander V. Chernikov break; 560*ac35ff17SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 561*ac35ff17SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 562*ac35ff17SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 563*ac35ff17SAlexander V. Chernikov memcpy(paddr, arg, mask); 564*ac35ff17SAlexander V. Chernikov /* Set mask to exact match */ 565*ac35ff17SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 566*ac35ff17SAlexander V. Chernikov break; 567*ac35ff17SAlexander V. Chernikov case IPFW_TABLE_U32: 568*ac35ff17SAlexander V. Chernikov /* Port or any other key */ 569*ac35ff17SAlexander V. Chernikov key = strtol(arg, &p, 10); 570*ac35ff17SAlexander V. Chernikov if (*p != '\0') 571*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid number: %s", arg); 572*ac35ff17SAlexander V. Chernikov 573*ac35ff17SAlexander V. Chernikov pkey = (uint32_t *)paddr; 574*ac35ff17SAlexander V. Chernikov *pkey = key; 575*ac35ff17SAlexander V. Chernikov masklen = 32; 576*ac35ff17SAlexander V. Chernikov break; 577*ac35ff17SAlexander V. Chernikov default: 578*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unsupported table type: %d", type); 579*ac35ff17SAlexander V. Chernikov } 580*ac35ff17SAlexander V. Chernikov 581*ac35ff17SAlexander V. Chernikov tentry->subtype = af; 582*ac35ff17SAlexander V. Chernikov tentry->masklen = masklen; 583*ac35ff17SAlexander V. Chernikov } 584*ac35ff17SAlexander V. Chernikov 585*ac35ff17SAlexander V. Chernikov static void 586*ac35ff17SAlexander V. Chernikov tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 587*ac35ff17SAlexander V. Chernikov uint8_t *ptype, uint8_t *pvtype) 588*ac35ff17SAlexander V. Chernikov { 589*ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 590*ac35ff17SAlexander V. Chernikov uint8_t type, vtype; 591*ac35ff17SAlexander V. Chernikov int error; 592*ac35ff17SAlexander V. Chernikov 593*ac35ff17SAlexander V. Chernikov type = 0; 594*ac35ff17SAlexander V. Chernikov vtype = 0; 595*ac35ff17SAlexander V. Chernikov 596*ac35ff17SAlexander V. Chernikov /* 597*ac35ff17SAlexander V. Chernikov * Compability layer. Try to interpret data as CIDR first. 598*ac35ff17SAlexander V. Chernikov */ 599*ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 || 600*ac35ff17SAlexander V. Chernikov inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { 601*ac35ff17SAlexander V. Chernikov /* OK Prepare and send */ 602*ac35ff17SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 603*ac35ff17SAlexander V. Chernikov } else { 604*ac35ff17SAlexander V. Chernikov 605*ac35ff17SAlexander V. Chernikov /* 606*ac35ff17SAlexander V. Chernikov * Non-CIDR of FQDN hostname. Ask kernel 607*ac35ff17SAlexander V. Chernikov * about given table. 608*ac35ff17SAlexander V. Chernikov */ 609*ac35ff17SAlexander V. Chernikov error = table_get_info(oh, &xi); 610*ac35ff17SAlexander V. Chernikov if (error == ESRCH) 611*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist, cannot intuit " 612*ac35ff17SAlexander V. Chernikov "key type", oh->ntlv.name); 613*ac35ff17SAlexander V. Chernikov else if (error != 0) 614*ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 615*ac35ff17SAlexander V. Chernikov oh->ntlv.name); 616*ac35ff17SAlexander V. Chernikov 617*ac35ff17SAlexander V. Chernikov /* Table found. */ 618*ac35ff17SAlexander V. Chernikov type = xi.type; 619*ac35ff17SAlexander V. Chernikov vtype = xi.vtype; 620*ac35ff17SAlexander V. Chernikov } 621*ac35ff17SAlexander V. Chernikov 622*ac35ff17SAlexander V. Chernikov tentry_fill_key_type(key, tent, type); 623*ac35ff17SAlexander V. Chernikov 624*ac35ff17SAlexander V. Chernikov *ptype = type; 625*ac35ff17SAlexander V. Chernikov *pvtype = vtype; 626*ac35ff17SAlexander V. Chernikov } 627*ac35ff17SAlexander V. Chernikov 628*ac35ff17SAlexander V. Chernikov static void 629*ac35ff17SAlexander V. Chernikov tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 630*ac35ff17SAlexander V. Chernikov uint8_t type, uint8_t vtype) 631*ac35ff17SAlexander V. Chernikov { 632*ac35ff17SAlexander V. Chernikov ipfw_xtable_info xi; 633*ac35ff17SAlexander V. Chernikov int error; 634*ac35ff17SAlexander V. Chernikov int code; 635*ac35ff17SAlexander V. Chernikov char *p; 636*ac35ff17SAlexander V. Chernikov 637*ac35ff17SAlexander V. Chernikov if (vtype == 0) { 638*ac35ff17SAlexander V. Chernikov /* Format type is unknown, ask kernel */ 639*ac35ff17SAlexander V. Chernikov error = table_get_info(oh, &xi); 640*ac35ff17SAlexander V. Chernikov if (error == ESRCH) { 641*ac35ff17SAlexander V. Chernikov 642*ac35ff17SAlexander V. Chernikov /* 643*ac35ff17SAlexander V. Chernikov * XXX: This one may break some scripts. 644*ac35ff17SAlexander V. Chernikov * Change this behavior for MFC. 645*ac35ff17SAlexander V. Chernikov */ 646*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Table %s does not exist. Unable to " 647*ac35ff17SAlexander V. Chernikov "guess value format.", oh->ntlv.name); 648*ac35ff17SAlexander V. Chernikov } else if (error != 0) 649*ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Error requesting table %s info", 650*ac35ff17SAlexander V. Chernikov oh->ntlv.name); 651*ac35ff17SAlexander V. Chernikov 652*ac35ff17SAlexander V. Chernikov vtype = xi.vtype; 653*ac35ff17SAlexander V. Chernikov } 654*ac35ff17SAlexander V. Chernikov 655*ac35ff17SAlexander V. Chernikov switch (vtype) { 656*ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_U32: 657*ac35ff17SAlexander V. Chernikov tent->value = strtoul(arg, &p, 0); 658*ac35ff17SAlexander V. Chernikov if (*p != '\0') 659*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid number: %s", arg); 660*ac35ff17SAlexander V. Chernikov break; 661*ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_IP: 662*ac35ff17SAlexander V. Chernikov if (inet_pton(AF_INET, arg, &tent->value) == 1) 663*ac35ff17SAlexander V. Chernikov break; 664*ac35ff17SAlexander V. Chernikov /* Try hostname */ 665*ac35ff17SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) 666*ac35ff17SAlexander V. Chernikov errx(EX_USAGE, "Invalid IPv4 address: %s", arg); 667*ac35ff17SAlexander V. Chernikov break; 668*ac35ff17SAlexander V. Chernikov case IPFW_VTYPE_DSCP: 669*ac35ff17SAlexander V. Chernikov if (isalpha(*arg)) { 670*ac35ff17SAlexander V. Chernikov if ((code = match_token(f_ipdscp, arg)) == -1) 671*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Unknown DSCP code"); 672*ac35ff17SAlexander V. Chernikov } else { 673*ac35ff17SAlexander V. Chernikov code = strtoul(arg, NULL, 10); 674*ac35ff17SAlexander V. Chernikov if (code < 0 || code > 63) 675*ac35ff17SAlexander V. Chernikov errx(EX_DATAERR, "Invalid DSCP value"); 676*ac35ff17SAlexander V. Chernikov } 677*ac35ff17SAlexander V. Chernikov tent->value = code; 678*ac35ff17SAlexander V. Chernikov break; 679*ac35ff17SAlexander V. Chernikov default: 680*ac35ff17SAlexander V. Chernikov errx(EX_OSERR, "Unsupported format type %d", vtype); 681*ac35ff17SAlexander V. Chernikov } 682*ac35ff17SAlexander V. Chernikov } 683f1220db8SAlexander V. Chernikov 684f1220db8SAlexander V. Chernikov /* 685f1220db8SAlexander V. Chernikov * Compare table names. 686f1220db8SAlexander V. Chernikov * Honor number comparison. 687f1220db8SAlexander V. Chernikov */ 688f1220db8SAlexander V. Chernikov static int 689f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 690f1220db8SAlexander V. Chernikov { 691f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 692f1220db8SAlexander V. Chernikov int la, lb; 693f1220db8SAlexander V. Chernikov 694f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 695f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 696f1220db8SAlexander V. Chernikov la = strlen(ia->tablename); 697f1220db8SAlexander V. Chernikov lb = strlen(ib->tablename); 698f1220db8SAlexander V. Chernikov 699f1220db8SAlexander V. Chernikov if (la > lb) 700f1220db8SAlexander V. Chernikov return (1); 701f1220db8SAlexander V. Chernikov else if (la < lb) 702f1220db8SAlexander V. Chernikov return (-01); 703f1220db8SAlexander V. Chernikov 704f1220db8SAlexander V. Chernikov return (strcmp(ia->tablename, ib->tablename)); 705f1220db8SAlexander V. Chernikov } 706f1220db8SAlexander V. Chernikov 707f1220db8SAlexander V. Chernikov /* 708f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 709f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 710f1220db8SAlexander V. Chernikov * Returns 0 on success. 711f1220db8SAlexander V. Chernikov */ 712f1220db8SAlexander V. Chernikov static int 713f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 714f1220db8SAlexander V. Chernikov { 715f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 716f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 717f1220db8SAlexander V. Chernikov size_t sz; 718f1220db8SAlexander V. Chernikov int i, error; 719f1220db8SAlexander V. Chernikov 720f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 721f1220db8SAlexander V. Chernikov sz = sizeof(req); 722f1220db8SAlexander V. Chernikov 723d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 724f1220db8SAlexander V. Chernikov return (errno); 725f1220db8SAlexander V. Chernikov 726f1220db8SAlexander V. Chernikov sz = req.size; 727f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 728f1220db8SAlexander V. Chernikov return (ENOMEM); 729f1220db8SAlexander V. Chernikov 730f1220db8SAlexander V. Chernikov olh->size = sz; 731d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 732f1220db8SAlexander V. Chernikov free(olh); 733f1220db8SAlexander V. Chernikov return (errno); 734f1220db8SAlexander V. Chernikov } 735f1220db8SAlexander V. Chernikov 736f1220db8SAlexander V. Chernikov if (sort != 0) 737f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 738f1220db8SAlexander V. Chernikov 739f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 740f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 741f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 742f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 743f1220db8SAlexander V. Chernikov } 744f1220db8SAlexander V. Chernikov 745f1220db8SAlexander V. Chernikov free(olh); 746f1220db8SAlexander V. Chernikov 747f1220db8SAlexander V. Chernikov return (0); 748f1220db8SAlexander V. Chernikov } 749f1220db8SAlexander V. Chernikov 750f1220db8SAlexander V. Chernikov /* 751f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 752d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 753d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 754f1220db8SAlexander V. Chernikov * 755f1220db8SAlexander V. Chernikov * Returns 0 on success. 756f1220db8SAlexander V. Chernikov */ 757f1220db8SAlexander V. Chernikov static int 758f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 759f1220db8SAlexander V. Chernikov { 760f1220db8SAlexander V. Chernikov size_t sz; 761f1220db8SAlexander V. Chernikov int error; 762f1220db8SAlexander V. Chernikov 763f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 764f1220db8SAlexander V. Chernikov sz = i->size; 765f1220db8SAlexander V. Chernikov 766d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 767d3a4f924SAlexander V. Chernikov 768d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0) 769f1220db8SAlexander V. Chernikov return (errno); 770f1220db8SAlexander V. Chernikov 771f1220db8SAlexander V. Chernikov return (0); 772f1220db8SAlexander V. Chernikov } 773f1220db8SAlexander V. Chernikov 774f1220db8SAlexander V. Chernikov /* 775f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 776f1220db8SAlexander V. Chernikov */ 777f1220db8SAlexander V. Chernikov static void 778f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 779f1220db8SAlexander V. Chernikov { 780f1220db8SAlexander V. Chernikov ipfw_table_xentry *xent; 781f1220db8SAlexander V. Chernikov uint32_t count, tval; 782f1220db8SAlexander V. Chernikov char tbuf[128]; 783f1220db8SAlexander V. Chernikov struct in6_addr *addr6; 784f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 785f1220db8SAlexander V. Chernikov 786f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 787f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)(i + 1); 788f1220db8SAlexander V. Chernikov 789f1220db8SAlexander V. Chernikov if (need_header) 790f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 791f1220db8SAlexander V. Chernikov 792f1220db8SAlexander V. Chernikov count = i->count; 793f1220db8SAlexander V. Chernikov while (count > 0) { 794f1220db8SAlexander V. Chernikov switch (i->type) { 795f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 796f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 797f1220db8SAlexander V. Chernikov tval = xent->value; 798f1220db8SAlexander V. Chernikov addr6 = &xent->k.addr6; 799f1220db8SAlexander V. Chernikov 800f1220db8SAlexander V. Chernikov 801f1220db8SAlexander V. Chernikov if ((xent->flags & IPFW_TCF_INET) != 0) { 802f1220db8SAlexander V. Chernikov /* IPv4 address */ 803f1220db8SAlexander V. Chernikov inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, 804f1220db8SAlexander V. Chernikov sizeof(tbuf)); 805f1220db8SAlexander V. Chernikov } else { 806f1220db8SAlexander V. Chernikov /* IPv6 address */ 807f1220db8SAlexander V. Chernikov inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf)); 808f1220db8SAlexander V. Chernikov } 809f1220db8SAlexander V. Chernikov 810f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 811f1220db8SAlexander V. Chernikov tval = htonl(tval); 812f1220db8SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, xent->masklen, 813f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 814f1220db8SAlexander V. Chernikov } else 815f1220db8SAlexander V. Chernikov printf("%s/%u %u\n", tbuf, xent->masklen, tval); 816f1220db8SAlexander V. Chernikov break; 817f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 818f1220db8SAlexander V. Chernikov /* Interface names */ 819f1220db8SAlexander V. Chernikov tval = xent->value; 820f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 821f1220db8SAlexander V. Chernikov tval = htonl(tval); 822f1220db8SAlexander V. Chernikov printf("%s %s\n", xent->k.iface, 823f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 824f1220db8SAlexander V. Chernikov } else 825f1220db8SAlexander V. Chernikov printf("%s %u\n", xent->k.iface, tval); 826f1220db8SAlexander V. Chernikov } 827f1220db8SAlexander V. Chernikov 828f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len); 829f1220db8SAlexander V. Chernikov count--; 830f1220db8SAlexander V. Chernikov } 831f1220db8SAlexander V. Chernikov } 832f1220db8SAlexander V. Chernikov 8336c2997ffSAlexander V. Chernikov int 8346c2997ffSAlexander V. Chernikov compare_ntlv(const void *_a, const void *_b) 8356c2997ffSAlexander V. Chernikov { 8366c2997ffSAlexander V. Chernikov ipfw_obj_ntlv *a, *b; 8376c2997ffSAlexander V. Chernikov 8386c2997ffSAlexander V. Chernikov a = (ipfw_obj_ntlv *)_a; 8396c2997ffSAlexander V. Chernikov b = (ipfw_obj_ntlv *)_b; 8406c2997ffSAlexander V. Chernikov 8416c2997ffSAlexander V. Chernikov if (a->set < b->set) 8426c2997ffSAlexander V. Chernikov return (-1); 8436c2997ffSAlexander V. Chernikov else if (a->set > b->set) 8446c2997ffSAlexander V. Chernikov return (1); 8456c2997ffSAlexander V. Chernikov 8466c2997ffSAlexander V. Chernikov if (a->idx < b->idx) 8476c2997ffSAlexander V. Chernikov return (-1); 8486c2997ffSAlexander V. Chernikov else if (a->idx > b->idx) 8496c2997ffSAlexander V. Chernikov return (1); 8506c2997ffSAlexander V. Chernikov 8516c2997ffSAlexander V. Chernikov return (0); 8526c2997ffSAlexander V. Chernikov } 853563b5ab1SAlexander V. Chernikov 854563b5ab1SAlexander V. Chernikov int 8556c2997ffSAlexander V. Chernikov compare_kntlv(const void *k, const void *v) 856563b5ab1SAlexander V. Chernikov { 857563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 858563b5ab1SAlexander V. Chernikov uint16_t key; 859563b5ab1SAlexander V. Chernikov 860563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 861563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 862563b5ab1SAlexander V. Chernikov 863563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 864563b5ab1SAlexander V. Chernikov return (-1); 865563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 866563b5ab1SAlexander V. Chernikov return (1); 867563b5ab1SAlexander V. Chernikov 868563b5ab1SAlexander V. Chernikov return (0); 869563b5ab1SAlexander V. Chernikov } 870563b5ab1SAlexander V. Chernikov 871563b5ab1SAlexander V. Chernikov /* 872563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 873563b5ab1SAlexander V. Chernikov * Uses the following facts: 874563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 875563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 876563b5ab1SAlexander V. Chernikov * 877563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 878563b5ab1SAlexander V. Chernikov */ 879563b5ab1SAlexander V. Chernikov char * 880563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 881563b5ab1SAlexander V. Chernikov { 882563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 883563b5ab1SAlexander V. Chernikov 884563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 8856c2997ffSAlexander V. Chernikov compare_kntlv); 886563b5ab1SAlexander V. Chernikov 887563b5ab1SAlexander V. Chernikov if (ntlv != 0) 888563b5ab1SAlexander V. Chernikov return (ntlv->name); 889563b5ab1SAlexander V. Chernikov 890563b5ab1SAlexander V. Chernikov return (NULL); 891563b5ab1SAlexander V. Chernikov } 892563b5ab1SAlexander V. Chernikov 8936c2997ffSAlexander V. Chernikov void 8946c2997ffSAlexander V. Chernikov table_sort_ctlv(ipfw_obj_ctlv *ctlv) 8956c2997ffSAlexander V. Chernikov { 8966c2997ffSAlexander V. Chernikov 8976c2997ffSAlexander V. Chernikov qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 8986c2997ffSAlexander V. Chernikov } 8996c2997ffSAlexander V. Chernikov 9006c2997ffSAlexander V. Chernikov int 9016c2997ffSAlexander V. Chernikov table_check_name(char *tablename) 9026c2997ffSAlexander V. Chernikov { 9036c2997ffSAlexander V. Chernikov int c, i, l; 9046c2997ffSAlexander V. Chernikov 9056c2997ffSAlexander V. Chernikov /* 9066c2997ffSAlexander V. Chernikov * Check if tablename is null-terminated and contains 9076c2997ffSAlexander V. Chernikov * valid symbols only. Valid mask is: 908*ac35ff17SAlexander V. Chernikov * [a-zA-Z0-9\-_\.]{1,63} 9096c2997ffSAlexander V. Chernikov */ 9106c2997ffSAlexander V. Chernikov l = strlen(tablename); 9116c2997ffSAlexander V. Chernikov if (l == 0 || l >= 64) 9126c2997ffSAlexander V. Chernikov return (EINVAL); 9136c2997ffSAlexander V. Chernikov for (i = 0; i < l; i++) { 9146c2997ffSAlexander V. Chernikov c = tablename[i]; 9156c2997ffSAlexander V. Chernikov if (isalpha(c) || isdigit(c) || c == '_' || 9166c2997ffSAlexander V. Chernikov c == '-' || c == '.') 9176c2997ffSAlexander V. Chernikov continue; 9186c2997ffSAlexander V. Chernikov return (EINVAL); 9196c2997ffSAlexander V. Chernikov } 9206c2997ffSAlexander V. Chernikov 921*ac35ff17SAlexander V. Chernikov /* Restrict some 'special' names */ 922*ac35ff17SAlexander V. Chernikov if (strcmp(tablename, "all") == 0) 923*ac35ff17SAlexander V. Chernikov return (EINVAL); 924*ac35ff17SAlexander V. Chernikov 9256c2997ffSAlexander V. Chernikov return (0); 9266c2997ffSAlexander V. Chernikov } 9276c2997ffSAlexander V. Chernikov 928