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); 52f1220db8SAlexander V. Chernikov static void table_fill_xentry(char *arg, ipfw_table_xentry *xent); 53f1220db8SAlexander V. Chernikov static int table_flush(char *name, uint32_t set); 54f1220db8SAlexander V. Chernikov static int table_destroy(char *name, uint32_t set); 55f1220db8SAlexander V. Chernikov static int table_get_info(char *name, uint32_t set, ipfw_xtable_info *i); 56f1220db8SAlexander V. Chernikov static int table_show_info(ipfw_xtable_info *i, void *arg); 57f1220db8SAlexander V. Chernikov static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx); 58f1220db8SAlexander V. Chernikov 59f1220db8SAlexander V. Chernikov static int table_flush_one(ipfw_xtable_info *i, void *arg); 60f1220db8SAlexander V. Chernikov static int table_show_one(ipfw_xtable_info *i, void *arg); 61f1220db8SAlexander V. Chernikov static int table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh); 62f1220db8SAlexander V. Chernikov static void table_show_list(ipfw_obj_header *oh, int need_header); 63f1220db8SAlexander V. Chernikov 64f1220db8SAlexander V. Chernikov typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 65f1220db8SAlexander V. Chernikov static int tables_foreach(table_cb_t *f, void *arg, int sort); 66f1220db8SAlexander V. Chernikov 67f1220db8SAlexander V. Chernikov #ifndef s6_addr32 68f1220db8SAlexander V. Chernikov #define s6_addr32 __u6_addr.__u6_addr32 69f1220db8SAlexander V. Chernikov #endif 70f1220db8SAlexander V. Chernikov 71f1220db8SAlexander V. Chernikov static int 72f1220db8SAlexander V. Chernikov lookup_host (char *host, struct in_addr *ipaddr) 73f1220db8SAlexander V. Chernikov { 74f1220db8SAlexander V. Chernikov struct hostent *he; 75f1220db8SAlexander V. Chernikov 76f1220db8SAlexander V. Chernikov if (!inet_aton(host, ipaddr)) { 77f1220db8SAlexander V. Chernikov if ((he = gethostbyname(host)) == NULL) 78f1220db8SAlexander V. Chernikov return(-1); 79f1220db8SAlexander V. Chernikov *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 80f1220db8SAlexander V. Chernikov } 81f1220db8SAlexander V. Chernikov return(0); 82f1220db8SAlexander V. Chernikov } 83f1220db8SAlexander V. Chernikov 84f1220db8SAlexander V. Chernikov /* 85f1220db8SAlexander V. Chernikov * This one handles all table-related commands 86f1220db8SAlexander V. Chernikov * ipfw table N add addr[/masklen] [value] 87f1220db8SAlexander V. Chernikov * ipfw table N delete addr[/masklen] 88f1220db8SAlexander V. Chernikov * ipfw table {N | all} flush 89f1220db8SAlexander V. Chernikov * ipfw table {N | all} list 90f1220db8SAlexander V. Chernikov * ipfw table {N | all} info 91f1220db8SAlexander V. Chernikov */ 92f1220db8SAlexander V. Chernikov void 93f1220db8SAlexander V. Chernikov ipfw_table_handler(int ac, char *av[]) 94f1220db8SAlexander V. Chernikov { 95f1220db8SAlexander V. Chernikov ipfw_table_xentry *xent; 96f1220db8SAlexander V. Chernikov int do_add; 97f1220db8SAlexander V. Chernikov int is_all; 98f1220db8SAlexander V. Chernikov uint32_t set; 99f1220db8SAlexander V. Chernikov int error; 100f1220db8SAlexander V. Chernikov char xbuf[sizeof(ip_fw3_opheader) + sizeof(ipfw_table_xentry)]; 101f1220db8SAlexander V. Chernikov ip_fw3_opheader *op3; 102f1220db8SAlexander V. Chernikov char *tablename; 103f1220db8SAlexander V. Chernikov 104f1220db8SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 105f1220db8SAlexander V. Chernikov op3 = (ip_fw3_opheader *)xbuf; 106f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)(op3 + 1); 107f1220db8SAlexander V. Chernikov 108f1220db8SAlexander V. Chernikov ac--; av++; 109f1220db8SAlexander V. Chernikov tablename = *av; 110f1220db8SAlexander V. Chernikov set = 0; 111f1220db8SAlexander V. Chernikov if (ac && isdigit(**av)) { 112f1220db8SAlexander V. Chernikov xent->tbl = atoi(*av); 113f1220db8SAlexander V. Chernikov is_all = 0; 114f1220db8SAlexander V. Chernikov ac--; av++; 115f1220db8SAlexander V. Chernikov } else if (ac && _substrcmp(*av, "all") == 0) { 116f1220db8SAlexander V. Chernikov xent->tbl = 0; 117f1220db8SAlexander V. Chernikov is_all = 1; 118f1220db8SAlexander V. Chernikov ac--; av++; 119f1220db8SAlexander V. Chernikov } else 120f1220db8SAlexander V. Chernikov errx(EX_USAGE, "table number or 'all' keyword required"); 121f1220db8SAlexander V. Chernikov NEED1("table needs command"); 122f1220db8SAlexander V. Chernikov if (is_all && _substrcmp(*av, "list") != 0 123f1220db8SAlexander V. Chernikov && _substrcmp(*av, "info") != 0 124f1220db8SAlexander V. Chernikov && _substrcmp(*av, "flush") != 0) 125f1220db8SAlexander V. Chernikov errx(EX_USAGE, "table number required"); 126f1220db8SAlexander V. Chernikov 127f1220db8SAlexander V. Chernikov if (_substrcmp(*av, "add") == 0 || 128f1220db8SAlexander V. Chernikov _substrcmp(*av, "delete") == 0) { 129f1220db8SAlexander V. Chernikov do_add = **av == 'a'; 130f1220db8SAlexander V. Chernikov ac--; av++; 131f1220db8SAlexander V. Chernikov if (!ac) 132f1220db8SAlexander V. Chernikov errx(EX_USAGE, "address required"); 133f1220db8SAlexander V. Chernikov 134f1220db8SAlexander V. Chernikov table_fill_xentry(*av, xent); 135f1220db8SAlexander V. Chernikov 136f1220db8SAlexander V. Chernikov ac--; av++; 137f1220db8SAlexander V. Chernikov if (do_add && ac) { 138f1220db8SAlexander V. Chernikov unsigned int tval; 139f1220db8SAlexander V. Chernikov /* isdigit is a bit of a hack here.. */ 140f1220db8SAlexander V. Chernikov if (strchr(*av, (int)'.') == NULL && isdigit(**av)) { 141f1220db8SAlexander V. Chernikov xent->value = strtoul(*av, NULL, 0); 142f1220db8SAlexander V. Chernikov } else { 143f1220db8SAlexander V. Chernikov if (lookup_host(*av, (struct in_addr *)&tval) == 0) { 144f1220db8SAlexander V. Chernikov /* The value must be stored in host order * 145f1220db8SAlexander V. Chernikov * so that the values < 65k can be distinguished */ 146f1220db8SAlexander V. Chernikov xent->value = ntohl(tval); 147f1220db8SAlexander V. Chernikov } else { 148f1220db8SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 149f1220db8SAlexander V. Chernikov } 150f1220db8SAlexander V. Chernikov } 151f1220db8SAlexander V. Chernikov } else 152f1220db8SAlexander V. Chernikov xent->value = 0; 153f1220db8SAlexander V. Chernikov if (do_set3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL, 154f1220db8SAlexander V. Chernikov op3, sizeof(xbuf)) < 0) { 155f1220db8SAlexander V. Chernikov /* If running silent, don't bomb out on these errors. */ 156f1220db8SAlexander V. Chernikov if (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) 157f1220db8SAlexander V. Chernikov err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", 158f1220db8SAlexander V. Chernikov do_add ? "XADD" : "XDEL"); 159f1220db8SAlexander V. Chernikov /* In silent mode, react to a failed add by deleting */ 160f1220db8SAlexander V. Chernikov if (do_add) { 161f1220db8SAlexander V. Chernikov do_set3(IP_FW_TABLE_XDEL, op3, sizeof(xbuf)); 162f1220db8SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XADD, op3, sizeof(xbuf)) < 0) 163f1220db8SAlexander V. Chernikov err(EX_OSERR, 164f1220db8SAlexander V. Chernikov "setsockopt(IP_FW_TABLE_XADD)"); 165f1220db8SAlexander V. Chernikov } 166f1220db8SAlexander V. Chernikov } 167f1220db8SAlexander V. Chernikov } else if (_substrcmp(*av, "flush") == 0) { 168f1220db8SAlexander V. Chernikov if (is_all == 0) { 169f1220db8SAlexander V. Chernikov if ((error = table_flush(tablename, set)) != 0) 170f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush table %s info", 171f1220db8SAlexander V. Chernikov tablename); 172f1220db8SAlexander V. Chernikov } else { 173f1220db8SAlexander V. Chernikov error = tables_foreach(table_flush_one, NULL, 1); 174f1220db8SAlexander V. Chernikov if (error != 0) 175f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to flush tables list"); 176f1220db8SAlexander V. Chernikov } 177f1220db8SAlexander V. Chernikov } else if (_substrcmp(*av, "list") == 0) { 178f1220db8SAlexander V. Chernikov if (is_all == 0) { 179f1220db8SAlexander V. Chernikov ipfw_xtable_info i; 180f1220db8SAlexander V. Chernikov if ((error = table_get_info(tablename, set, &i)) != 0) 181f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 182f1220db8SAlexander V. Chernikov table_show_one(&i, NULL); 183f1220db8SAlexander V. Chernikov } else { 184f1220db8SAlexander V. Chernikov error = tables_foreach(table_show_one, NULL, 1); 185f1220db8SAlexander V. Chernikov if (error != 0) 186f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 187f1220db8SAlexander V. Chernikov } 188f1220db8SAlexander V. Chernikov } else if (_substrcmp(*av, "destroy") == 0) { 189f1220db8SAlexander V. Chernikov if (table_destroy(tablename, set) != 0) 190f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to destroy table %s", tablename); 191f1220db8SAlexander V. Chernikov } else if (_substrcmp(*av, "info") == 0) { 192f1220db8SAlexander V. Chernikov if (is_all == 0) { 193f1220db8SAlexander V. Chernikov ipfw_xtable_info i; 194f1220db8SAlexander V. Chernikov if ((error = table_get_info(tablename, set, &i)) != 0) 195f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request table info"); 196f1220db8SAlexander V. Chernikov table_show_info(&i, NULL); 197f1220db8SAlexander V. Chernikov } else { 198f1220db8SAlexander V. Chernikov error = tables_foreach(table_show_info, NULL, 1); 199f1220db8SAlexander V. Chernikov if (error != 0) 200f1220db8SAlexander V. Chernikov err(EX_OSERR, "failed to request tables list"); 201f1220db8SAlexander V. Chernikov } 202f1220db8SAlexander V. Chernikov } else 203f1220db8SAlexander V. Chernikov errx(EX_USAGE, "invalid table command %s", *av); 204f1220db8SAlexander V. Chernikov } 205f1220db8SAlexander V. Chernikov 206f1220db8SAlexander V. Chernikov static void 207f1220db8SAlexander V. Chernikov table_fill_xentry(char *arg, ipfw_table_xentry *xent) 208f1220db8SAlexander V. Chernikov { 209f1220db8SAlexander V. Chernikov int addrlen, mask, masklen, type; 210f1220db8SAlexander V. Chernikov struct in6_addr *paddr; 211f1220db8SAlexander V. Chernikov uint32_t *pkey; 212f1220db8SAlexander V. Chernikov char *p; 213f1220db8SAlexander V. Chernikov uint32_t key; 214f1220db8SAlexander V. Chernikov 215f1220db8SAlexander V. Chernikov mask = 0; 216f1220db8SAlexander V. Chernikov type = 0; 217f1220db8SAlexander V. Chernikov addrlen = 0; 218f1220db8SAlexander V. Chernikov masklen = 0; 219f1220db8SAlexander V. Chernikov 220f1220db8SAlexander V. Chernikov /* 221f1220db8SAlexander V. Chernikov * Let's try to guess type by agrument. 222f1220db8SAlexander V. Chernikov * Possible types: 223f1220db8SAlexander V. Chernikov * 1) IPv4[/mask] 224f1220db8SAlexander V. Chernikov * 2) IPv6[/mask] 225f1220db8SAlexander V. Chernikov * 3) interface name 226f1220db8SAlexander V. Chernikov * 4) port, uid/gid or other u32 key (base 10 format) 227f1220db8SAlexander V. Chernikov * 5) hostname 228f1220db8SAlexander V. Chernikov */ 229f1220db8SAlexander V. Chernikov paddr = &xent->k.addr6; 230f1220db8SAlexander V. Chernikov if (ishexnumber(*arg) != 0 || *arg == ':') { 231f1220db8SAlexander V. Chernikov /* Remove / if exists */ 232f1220db8SAlexander V. Chernikov if ((p = strchr(arg, '/')) != NULL) { 233f1220db8SAlexander V. Chernikov *p = '\0'; 234f1220db8SAlexander V. Chernikov mask = atoi(p + 1); 235f1220db8SAlexander V. Chernikov } 236f1220db8SAlexander V. Chernikov 237f1220db8SAlexander V. Chernikov if (inet_pton(AF_INET, arg, paddr) == 1) { 238f1220db8SAlexander V. Chernikov if (p != NULL && mask > 32) 239f1220db8SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv4 mask width: %s", 240f1220db8SAlexander V. Chernikov p + 1); 241f1220db8SAlexander V. Chernikov 242f1220db8SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 243f1220db8SAlexander V. Chernikov masklen = p ? mask : 32; 244f1220db8SAlexander V. Chernikov addrlen = sizeof(struct in_addr); 245f1220db8SAlexander V. Chernikov } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 246f1220db8SAlexander V. Chernikov if (IN6_IS_ADDR_V4COMPAT(paddr)) 247f1220db8SAlexander V. Chernikov errx(EX_DATAERR, 248f1220db8SAlexander V. Chernikov "Use IPv4 instead of v4-compatible"); 249f1220db8SAlexander V. Chernikov if (p != NULL && mask > 128) 250f1220db8SAlexander V. Chernikov errx(EX_DATAERR, "bad IPv6 mask width: %s", 251f1220db8SAlexander V. Chernikov p + 1); 252f1220db8SAlexander V. Chernikov 253f1220db8SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 254f1220db8SAlexander V. Chernikov masklen = p ? mask : 128; 255f1220db8SAlexander V. Chernikov addrlen = sizeof(struct in6_addr); 256f1220db8SAlexander V. Chernikov } else { 257f1220db8SAlexander V. Chernikov /* Port or any other key */ 258f1220db8SAlexander V. Chernikov /* Skip non-base 10 entries like 'fa1' */ 259f1220db8SAlexander V. Chernikov key = strtol(arg, &p, 10); 260f1220db8SAlexander V. Chernikov if (*p == '\0') { 261f1220db8SAlexander V. Chernikov pkey = (uint32_t *)paddr; 262f1220db8SAlexander V. Chernikov *pkey = htonl(key); 263f1220db8SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 264f1220db8SAlexander V. Chernikov masklen = 32; 265f1220db8SAlexander V. Chernikov addrlen = sizeof(uint32_t); 266f1220db8SAlexander V. Chernikov } else if ((p != arg) && (*p == '.')) { 267f1220db8SAlexander V. Chernikov /* 268f1220db8SAlexander V. Chernikov * Warn on IPv4 address strings 269f1220db8SAlexander V. Chernikov * which are "valid" for inet_aton() but not 270f1220db8SAlexander V. Chernikov * in inet_pton(). 271f1220db8SAlexander V. Chernikov * 272f1220db8SAlexander V. Chernikov * Typical examples: '10.5' or '10.0.0.05' 273f1220db8SAlexander V. Chernikov */ 274f1220db8SAlexander V. Chernikov errx(EX_DATAERR, 275f1220db8SAlexander V. Chernikov "Invalid IPv4 address: %s", arg); 276f1220db8SAlexander V. Chernikov } 277f1220db8SAlexander V. Chernikov } 278f1220db8SAlexander V. Chernikov } 279f1220db8SAlexander V. Chernikov 280f1220db8SAlexander V. Chernikov if (type == 0 && strchr(arg, '.') == NULL) { 281f1220db8SAlexander V. Chernikov /* Assume interface name. Copy significant data only */ 282f1220db8SAlexander V. Chernikov mask = MIN(strlen(arg), IF_NAMESIZE - 1); 283f1220db8SAlexander V. Chernikov memcpy(xent->k.iface, arg, mask); 284f1220db8SAlexander V. Chernikov /* Set mask to exact match */ 285f1220db8SAlexander V. Chernikov masklen = 8 * IF_NAMESIZE; 286f1220db8SAlexander V. Chernikov type = IPFW_TABLE_INTERFACE; 287f1220db8SAlexander V. Chernikov addrlen = IF_NAMESIZE; 288f1220db8SAlexander V. Chernikov } 289f1220db8SAlexander V. Chernikov 290f1220db8SAlexander V. Chernikov if (type == 0) { 291f1220db8SAlexander V. Chernikov if (lookup_host(arg, (struct in_addr *)paddr) != 0) 292f1220db8SAlexander V. Chernikov errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 293f1220db8SAlexander V. Chernikov 294f1220db8SAlexander V. Chernikov masklen = 32; 295f1220db8SAlexander V. Chernikov type = IPFW_TABLE_CIDR; 296f1220db8SAlexander V. Chernikov addrlen = sizeof(struct in_addr); 297f1220db8SAlexander V. Chernikov } 298f1220db8SAlexander V. Chernikov 299f1220db8SAlexander V. Chernikov xent->type = type; 300f1220db8SAlexander V. Chernikov xent->masklen = masklen; 301f1220db8SAlexander V. Chernikov xent->len = offsetof(ipfw_table_xentry, k) + addrlen; 302f1220db8SAlexander V. Chernikov } 303f1220db8SAlexander V. Chernikov 304f1220db8SAlexander V. Chernikov static void 305f1220db8SAlexander V. Chernikov table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx) 306f1220db8SAlexander V. Chernikov { 307f1220db8SAlexander V. Chernikov 308*563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 309f1220db8SAlexander V. Chernikov ntlv->head.length = sizeof(ipfw_obj_ntlv); 310f1220db8SAlexander V. Chernikov ntlv->idx = uidx; 311f1220db8SAlexander V. Chernikov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 312f1220db8SAlexander V. Chernikov } 313f1220db8SAlexander V. Chernikov 314f1220db8SAlexander V. Chernikov static void 315f1220db8SAlexander V. Chernikov table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 316f1220db8SAlexander V. Chernikov { 317f1220db8SAlexander V. Chernikov 318f1220db8SAlexander V. Chernikov oh->set = i->set; 319f1220db8SAlexander V. Chernikov oh->idx = 1; 320f1220db8SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, 1); 321f1220db8SAlexander V. Chernikov } 322f1220db8SAlexander V. Chernikov 323f1220db8SAlexander V. Chernikov /* 324f1220db8SAlexander V. Chernikov * Destroys given table @name in given @set. 325f1220db8SAlexander V. Chernikov * Returns 0 on success. 326f1220db8SAlexander V. Chernikov */ 327f1220db8SAlexander V. Chernikov static int 328f1220db8SAlexander V. Chernikov table_destroy(char *name, uint32_t set) 329f1220db8SAlexander V. Chernikov { 330f1220db8SAlexander V. Chernikov ipfw_obj_header oh; 331f1220db8SAlexander V. Chernikov 332f1220db8SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 333f1220db8SAlexander V. Chernikov oh.idx = 1; 334f1220db8SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, name, 1); 335d3a4f924SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XDESTROY, &oh.opheader, sizeof(oh)) != 0) 336f1220db8SAlexander V. Chernikov return (-1); 337f1220db8SAlexander V. Chernikov 338f1220db8SAlexander V. Chernikov return (0); 339f1220db8SAlexander V. Chernikov } 340f1220db8SAlexander V. Chernikov 341f1220db8SAlexander V. Chernikov /* 342f1220db8SAlexander V. Chernikov * Flushes given table @name in given @set. 343f1220db8SAlexander V. Chernikov * Returns 0 on success. 344f1220db8SAlexander V. Chernikov */ 345f1220db8SAlexander V. Chernikov static int 346f1220db8SAlexander V. Chernikov table_flush(char *name, uint32_t set) 347f1220db8SAlexander V. Chernikov { 348f1220db8SAlexander V. Chernikov ipfw_obj_header oh; 349f1220db8SAlexander V. Chernikov 350f1220db8SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 351f1220db8SAlexander V. Chernikov oh.idx = 1; 352f1220db8SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, name, 1); 353d3a4f924SAlexander V. Chernikov if (do_set3(IP_FW_TABLE_XFLUSH, &oh.opheader, sizeof(oh)) != 0) 354f1220db8SAlexander V. Chernikov return (-1); 355f1220db8SAlexander V. Chernikov 356f1220db8SAlexander V. Chernikov return (0); 357f1220db8SAlexander V. Chernikov } 358f1220db8SAlexander V. Chernikov 359f1220db8SAlexander V. Chernikov /* 360f1220db8SAlexander V. Chernikov * Retrieves info for given table @name in given @set and stores 361f1220db8SAlexander V. Chernikov * it inside @i. 362f1220db8SAlexander V. Chernikov * Returns 0 on success. 363f1220db8SAlexander V. Chernikov */ 364f1220db8SAlexander V. Chernikov static int 365f1220db8SAlexander V. Chernikov table_get_info(char *name, uint32_t set, ipfw_xtable_info *i) 366f1220db8SAlexander V. Chernikov { 367f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header)+sizeof(ipfw_xtable_info)]; 368f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 369f1220db8SAlexander V. Chernikov size_t sz; 370f1220db8SAlexander V. Chernikov 371f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 372f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 373f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 374f1220db8SAlexander V. Chernikov 375f1220db8SAlexander V. Chernikov i->set = set; 376f1220db8SAlexander V. Chernikov strlcpy(i->tablename, name, sizeof(i->tablename)); 377f1220db8SAlexander V. Chernikov 378f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 379f1220db8SAlexander V. Chernikov 380d3a4f924SAlexander V. Chernikov if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) < 0) 381f1220db8SAlexander V. Chernikov return (-1); 382f1220db8SAlexander V. Chernikov 383f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 384f1220db8SAlexander V. Chernikov return (-1); 385f1220db8SAlexander V. Chernikov 386f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 387f1220db8SAlexander V. Chernikov 388f1220db8SAlexander V. Chernikov return (0); 389f1220db8SAlexander V. Chernikov } 390f1220db8SAlexander V. Chernikov 391f1220db8SAlexander V. Chernikov /* 392f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 393f1220db8SAlexander V. Chernikov */ 394f1220db8SAlexander V. Chernikov static int 395f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 396f1220db8SAlexander V. Chernikov { 397f1220db8SAlexander V. Chernikov char *type; 398f1220db8SAlexander V. Chernikov 399f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 400f1220db8SAlexander V. Chernikov switch (i->type) { 401f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 402f1220db8SAlexander V. Chernikov type = "cidr"; 403f1220db8SAlexander V. Chernikov break; 404f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 405f1220db8SAlexander V. Chernikov type = "iface"; 406f1220db8SAlexander V. Chernikov break; 407f1220db8SAlexander V. Chernikov default: 408f1220db8SAlexander V. Chernikov type = "unknown"; 409f1220db8SAlexander V. Chernikov } 410f1220db8SAlexander V. Chernikov printf(" type: %s, kindex: %d\n", type, i->kidx); 411f1220db8SAlexander V. Chernikov printf(" ftype: %d, algorithm: %d\n", i->ftype, i->atype); 412f1220db8SAlexander V. Chernikov printf(" references: %u\n", i->refcnt); 413f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 414f1220db8SAlexander V. Chernikov 415f1220db8SAlexander V. Chernikov return (0); 416f1220db8SAlexander V. Chernikov } 417f1220db8SAlexander V. Chernikov 418f1220db8SAlexander V. Chernikov 419f1220db8SAlexander V. Chernikov /* 420f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 421f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 422f1220db8SAlexander V. Chernikov */ 423f1220db8SAlexander V. Chernikov 424f1220db8SAlexander V. Chernikov static int 425f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 426f1220db8SAlexander V. Chernikov { 427f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 428f1220db8SAlexander V. Chernikov 429f1220db8SAlexander V. Chernikov if ((oh = malloc(i->size)) == NULL) 430f1220db8SAlexander V. Chernikov return (ENOMEM); 431f1220db8SAlexander V. Chernikov 432f1220db8SAlexander V. Chernikov if (table_get_list(i, oh) == 0) 433f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 434f1220db8SAlexander V. Chernikov 435f1220db8SAlexander V. Chernikov free(oh); 436f1220db8SAlexander V. Chernikov return (0); 437f1220db8SAlexander V. Chernikov } 438f1220db8SAlexander V. Chernikov 439f1220db8SAlexander V. Chernikov static int 440f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 441f1220db8SAlexander V. Chernikov { 442f1220db8SAlexander V. Chernikov 443f1220db8SAlexander V. Chernikov return (table_flush(i->tablename, i->set)); 444f1220db8SAlexander V. Chernikov } 445f1220db8SAlexander V. Chernikov 446f1220db8SAlexander V. Chernikov 447f1220db8SAlexander V. Chernikov /* 448f1220db8SAlexander V. Chernikov * Compare table names. 449f1220db8SAlexander V. Chernikov * Honor number comparison. 450f1220db8SAlexander V. Chernikov */ 451f1220db8SAlexander V. Chernikov static int 452f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 453f1220db8SAlexander V. Chernikov { 454f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 455f1220db8SAlexander V. Chernikov int la, lb; 456f1220db8SAlexander V. Chernikov 457f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 458f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 459f1220db8SAlexander V. Chernikov la = strlen(ia->tablename); 460f1220db8SAlexander V. Chernikov lb = strlen(ib->tablename); 461f1220db8SAlexander V. Chernikov 462f1220db8SAlexander V. Chernikov if (la > lb) 463f1220db8SAlexander V. Chernikov return (1); 464f1220db8SAlexander V. Chernikov else if (la < lb) 465f1220db8SAlexander V. Chernikov return (-01); 466f1220db8SAlexander V. Chernikov 467f1220db8SAlexander V. Chernikov return (strcmp(ia->tablename, ib->tablename)); 468f1220db8SAlexander V. Chernikov } 469f1220db8SAlexander V. Chernikov 470f1220db8SAlexander V. Chernikov /* 471f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 472f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 473f1220db8SAlexander V. Chernikov * Returns 0 on success. 474f1220db8SAlexander V. Chernikov */ 475f1220db8SAlexander V. Chernikov static int 476f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 477f1220db8SAlexander V. Chernikov { 478f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 479f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 480f1220db8SAlexander V. Chernikov size_t sz; 481f1220db8SAlexander V. Chernikov int i, error; 482f1220db8SAlexander V. Chernikov 483f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 484f1220db8SAlexander V. Chernikov sz = sizeof(req); 485f1220db8SAlexander V. Chernikov 486d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XGETSIZE, &req.opheader, &sz)) != 0) 487f1220db8SAlexander V. Chernikov return (errno); 488f1220db8SAlexander V. Chernikov 489f1220db8SAlexander V. Chernikov sz = req.size; 490f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 491f1220db8SAlexander V. Chernikov return (ENOMEM); 492f1220db8SAlexander V. Chernikov 493f1220db8SAlexander V. Chernikov olh->size = sz; 494d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz)) != 0) { 495f1220db8SAlexander V. Chernikov free(olh); 496f1220db8SAlexander V. Chernikov return (errno); 497f1220db8SAlexander V. Chernikov } 498f1220db8SAlexander V. Chernikov 499f1220db8SAlexander V. Chernikov if (sort != 0) 500f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 501f1220db8SAlexander V. Chernikov 502f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 503f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 504f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 505f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 506f1220db8SAlexander V. Chernikov } 507f1220db8SAlexander V. Chernikov 508f1220db8SAlexander V. Chernikov free(olh); 509f1220db8SAlexander V. Chernikov 510f1220db8SAlexander V. Chernikov return (0); 511f1220db8SAlexander V. Chernikov } 512f1220db8SAlexander V. Chernikov 513f1220db8SAlexander V. Chernikov /* 514f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 515d3a4f924SAlexander V. Chernikov * eXtended format. Assumes buffer of size 516d3a4f924SAlexander V. Chernikov * @i->size has already been allocated by caller. 517f1220db8SAlexander V. Chernikov * 518f1220db8SAlexander V. Chernikov * Returns 0 on success. 519f1220db8SAlexander V. Chernikov */ 520f1220db8SAlexander V. Chernikov static int 521f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 522f1220db8SAlexander V. Chernikov { 523f1220db8SAlexander V. Chernikov size_t sz; 524f1220db8SAlexander V. Chernikov int error; 525f1220db8SAlexander V. Chernikov 526f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 527f1220db8SAlexander V. Chernikov sz = i->size; 528f1220db8SAlexander V. Chernikov 529d3a4f924SAlexander V. Chernikov oh->opheader.version = 1; /* Current version */ 530d3a4f924SAlexander V. Chernikov 531d3a4f924SAlexander V. Chernikov if ((error = do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz)) != 0) 532f1220db8SAlexander V. Chernikov return (errno); 533f1220db8SAlexander V. Chernikov 534f1220db8SAlexander V. Chernikov return (0); 535f1220db8SAlexander V. Chernikov } 536f1220db8SAlexander V. Chernikov 537f1220db8SAlexander V. Chernikov /* 538f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 539f1220db8SAlexander V. Chernikov */ 540f1220db8SAlexander V. Chernikov static void 541f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 542f1220db8SAlexander V. Chernikov { 543f1220db8SAlexander V. Chernikov ipfw_table_xentry *xent; 544f1220db8SAlexander V. Chernikov uint32_t count, tval; 545f1220db8SAlexander V. Chernikov char tbuf[128]; 546f1220db8SAlexander V. Chernikov struct in6_addr *addr6; 547f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 548f1220db8SAlexander V. Chernikov 549f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 550f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)(i + 1); 551f1220db8SAlexander V. Chernikov 552f1220db8SAlexander V. Chernikov if (need_header) 553f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 554f1220db8SAlexander V. Chernikov 555f1220db8SAlexander V. Chernikov count = i->count; 556f1220db8SAlexander V. Chernikov while (count > 0) { 557f1220db8SAlexander V. Chernikov switch (i->type) { 558f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 559f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 560f1220db8SAlexander V. Chernikov tval = xent->value; 561f1220db8SAlexander V. Chernikov addr6 = &xent->k.addr6; 562f1220db8SAlexander V. Chernikov 563f1220db8SAlexander V. Chernikov 564f1220db8SAlexander V. Chernikov if ((xent->flags & IPFW_TCF_INET) != 0) { 565f1220db8SAlexander V. Chernikov /* IPv4 address */ 566f1220db8SAlexander V. Chernikov inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, 567f1220db8SAlexander V. Chernikov sizeof(tbuf)); 568f1220db8SAlexander V. Chernikov } else { 569f1220db8SAlexander V. Chernikov /* IPv6 address */ 570f1220db8SAlexander V. Chernikov inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf)); 571f1220db8SAlexander V. Chernikov } 572f1220db8SAlexander V. Chernikov 573f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 574f1220db8SAlexander V. Chernikov tval = htonl(tval); 575f1220db8SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, xent->masklen, 576f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 577f1220db8SAlexander V. Chernikov } else 578f1220db8SAlexander V. Chernikov printf("%s/%u %u\n", tbuf, xent->masklen, tval); 579f1220db8SAlexander V. Chernikov break; 580f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 581f1220db8SAlexander V. Chernikov /* Interface names */ 582f1220db8SAlexander V. Chernikov tval = xent->value; 583f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 584f1220db8SAlexander V. Chernikov tval = htonl(tval); 585f1220db8SAlexander V. Chernikov printf("%s %s\n", xent->k.iface, 586f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 587f1220db8SAlexander V. Chernikov } else 588f1220db8SAlexander V. Chernikov printf("%s %u\n", xent->k.iface, tval); 589f1220db8SAlexander V. Chernikov } 590f1220db8SAlexander V. Chernikov 591f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len); 592f1220db8SAlexander V. Chernikov count--; 593f1220db8SAlexander V. Chernikov } 594f1220db8SAlexander V. Chernikov } 595f1220db8SAlexander V. Chernikov 596*563b5ab1SAlexander V. Chernikov 597*563b5ab1SAlexander V. Chernikov int 598*563b5ab1SAlexander V. Chernikov compare_ntlv(const void *k, const void *v) 599*563b5ab1SAlexander V. Chernikov { 600*563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 601*563b5ab1SAlexander V. Chernikov uint16_t key; 602*563b5ab1SAlexander V. Chernikov 603*563b5ab1SAlexander V. Chernikov key = *((uint16_t *)k); 604*563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)v; 605*563b5ab1SAlexander V. Chernikov 606*563b5ab1SAlexander V. Chernikov if (key < ntlv->idx) 607*563b5ab1SAlexander V. Chernikov return (-1); 608*563b5ab1SAlexander V. Chernikov else if (key > ntlv->idx) 609*563b5ab1SAlexander V. Chernikov return (1); 610*563b5ab1SAlexander V. Chernikov 611*563b5ab1SAlexander V. Chernikov return (0); 612*563b5ab1SAlexander V. Chernikov } 613*563b5ab1SAlexander V. Chernikov 614*563b5ab1SAlexander V. Chernikov /* 615*563b5ab1SAlexander V. Chernikov * Finds table name in @ctlv by @idx. 616*563b5ab1SAlexander V. Chernikov * Uses the following facts: 617*563b5ab1SAlexander V. Chernikov * 1) All TLVs are the same size 618*563b5ab1SAlexander V. Chernikov * 2) Kernel implementation provides already sorted list. 619*563b5ab1SAlexander V. Chernikov * 620*563b5ab1SAlexander V. Chernikov * Returns table name or NULL. 621*563b5ab1SAlexander V. Chernikov */ 622*563b5ab1SAlexander V. Chernikov char * 623*563b5ab1SAlexander V. Chernikov table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 624*563b5ab1SAlexander V. Chernikov { 625*563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 626*563b5ab1SAlexander V. Chernikov 627*563b5ab1SAlexander V. Chernikov ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize, 628*563b5ab1SAlexander V. Chernikov compare_ntlv); 629*563b5ab1SAlexander V. Chernikov 630*563b5ab1SAlexander V. Chernikov if (ntlv != 0) 631*563b5ab1SAlexander V. Chernikov return (ntlv->name); 632*563b5ab1SAlexander V. Chernikov 633*563b5ab1SAlexander V. Chernikov return (NULL); 634*563b5ab1SAlexander V. Chernikov } 635*563b5ab1SAlexander V. Chernikov 636