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 308f1220db8SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_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 oh->objtype = IPFW_OBJTYPE_TABLE; 321f1220db8SAlexander V. Chernikov table_fill_ntlv(&oh->ntlv, i->tablename, 1); 322f1220db8SAlexander V. Chernikov } 323f1220db8SAlexander V. Chernikov 324f1220db8SAlexander V. Chernikov /* 325f1220db8SAlexander V. Chernikov * Destroys given table @name in given @set. 326f1220db8SAlexander V. Chernikov * Returns 0 on success. 327f1220db8SAlexander V. Chernikov */ 328f1220db8SAlexander V. Chernikov static int 329f1220db8SAlexander V. Chernikov table_destroy(char *name, uint32_t set) 330f1220db8SAlexander V. Chernikov { 331f1220db8SAlexander V. Chernikov ipfw_obj_header oh; 332f1220db8SAlexander V. Chernikov 333f1220db8SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 334f1220db8SAlexander V. Chernikov oh.idx = 1; 335f1220db8SAlexander V. Chernikov oh.objtype = IPFW_OBJTYPE_TABLE; 336f1220db8SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, name, 1); 337f1220db8SAlexander V. Chernikov if (do_set3(IP_FW_OBJ_DEL, &oh.opheader, sizeof(oh)) != 0) 338f1220db8SAlexander V. Chernikov return (-1); 339f1220db8SAlexander V. Chernikov 340f1220db8SAlexander V. Chernikov return (0); 341f1220db8SAlexander V. Chernikov } 342f1220db8SAlexander V. Chernikov 343f1220db8SAlexander V. Chernikov /* 344f1220db8SAlexander V. Chernikov * Flushes given table @name in given @set. 345f1220db8SAlexander V. Chernikov * Returns 0 on success. 346f1220db8SAlexander V. Chernikov */ 347f1220db8SAlexander V. Chernikov static int 348f1220db8SAlexander V. Chernikov table_flush(char *name, uint32_t set) 349f1220db8SAlexander V. Chernikov { 350f1220db8SAlexander V. Chernikov ipfw_obj_header oh; 351f1220db8SAlexander V. Chernikov 352f1220db8SAlexander V. Chernikov memset(&oh, 0, sizeof(oh)); 353f1220db8SAlexander V. Chernikov oh.idx = 1; 354f1220db8SAlexander V. Chernikov oh.objtype = IPFW_OBJTYPE_TABLE; 355f1220db8SAlexander V. Chernikov table_fill_ntlv(&oh.ntlv, name, 1); 356f1220db8SAlexander V. Chernikov if (do_set3(IP_FW_OBJ_FLUSH, &oh.opheader, sizeof(oh)) != 0) 357f1220db8SAlexander V. Chernikov return (-1); 358f1220db8SAlexander V. Chernikov 359f1220db8SAlexander V. Chernikov return (0); 360f1220db8SAlexander V. Chernikov } 361f1220db8SAlexander V. Chernikov 362f1220db8SAlexander V. Chernikov /* 363f1220db8SAlexander V. Chernikov * Retrieves info for given table @name in given @set and stores 364f1220db8SAlexander V. Chernikov * it inside @i. 365f1220db8SAlexander V. Chernikov * Returns 0 on success. 366f1220db8SAlexander V. Chernikov */ 367f1220db8SAlexander V. Chernikov static int 368f1220db8SAlexander V. Chernikov table_get_info(char *name, uint32_t set, ipfw_xtable_info *i) 369f1220db8SAlexander V. Chernikov { 370f1220db8SAlexander V. Chernikov char tbuf[sizeof(ipfw_obj_header)+sizeof(ipfw_xtable_info)]; 371f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 372f1220db8SAlexander V. Chernikov size_t sz; 373f1220db8SAlexander V. Chernikov 374f1220db8SAlexander V. Chernikov sz = sizeof(tbuf); 375f1220db8SAlexander V. Chernikov memset(tbuf, 0, sizeof(tbuf)); 376f1220db8SAlexander V. Chernikov oh = (ipfw_obj_header *)tbuf; 377f1220db8SAlexander V. Chernikov 378f1220db8SAlexander V. Chernikov i->set = set; 379f1220db8SAlexander V. Chernikov strlcpy(i->tablename, name, sizeof(i->tablename)); 380f1220db8SAlexander V. Chernikov 381f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 382f1220db8SAlexander V. Chernikov 383f1220db8SAlexander V. Chernikov if (do_get3(IP_FW_OBJ_INFO, &oh->opheader, &sz) < 0) 384f1220db8SAlexander V. Chernikov return (-1); 385f1220db8SAlexander V. Chernikov 386f1220db8SAlexander V. Chernikov if (sz < sizeof(tbuf)) 387f1220db8SAlexander V. Chernikov return (-1); 388f1220db8SAlexander V. Chernikov 389f1220db8SAlexander V. Chernikov *i = *(ipfw_xtable_info *)(oh + 1); 390f1220db8SAlexander V. Chernikov 391f1220db8SAlexander V. Chernikov return (0); 392f1220db8SAlexander V. Chernikov } 393f1220db8SAlexander V. Chernikov 394f1220db8SAlexander V. Chernikov /* 395f1220db8SAlexander V. Chernikov * Prints table info struct @i in human-readable form. 396f1220db8SAlexander V. Chernikov */ 397f1220db8SAlexander V. Chernikov static int 398f1220db8SAlexander V. Chernikov table_show_info(ipfw_xtable_info *i, void *arg) 399f1220db8SAlexander V. Chernikov { 400f1220db8SAlexander V. Chernikov char *type; 401f1220db8SAlexander V. Chernikov 402f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 403f1220db8SAlexander V. Chernikov switch (i->type) { 404f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 405f1220db8SAlexander V. Chernikov type = "cidr"; 406f1220db8SAlexander V. Chernikov break; 407f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 408f1220db8SAlexander V. Chernikov type = "iface"; 409f1220db8SAlexander V. Chernikov break; 410f1220db8SAlexander V. Chernikov default: 411f1220db8SAlexander V. Chernikov type = "unknown"; 412f1220db8SAlexander V. Chernikov } 413f1220db8SAlexander V. Chernikov printf(" type: %s, kindex: %d\n", type, i->kidx); 414f1220db8SAlexander V. Chernikov printf(" ftype: %d, algorithm: %d\n", i->ftype, i->atype); 415f1220db8SAlexander V. Chernikov printf(" references: %u\n", i->refcnt); 416f1220db8SAlexander V. Chernikov printf(" items: %u, size: %u\n", i->count, i->size); 417f1220db8SAlexander V. Chernikov 418f1220db8SAlexander V. Chernikov return (0); 419f1220db8SAlexander V. Chernikov } 420f1220db8SAlexander V. Chernikov 421f1220db8SAlexander V. Chernikov 422f1220db8SAlexander V. Chernikov /* 423f1220db8SAlexander V. Chernikov * Function wrappers which can be used either 424f1220db8SAlexander V. Chernikov * as is or as foreach function parameter. 425f1220db8SAlexander V. Chernikov */ 426f1220db8SAlexander V. Chernikov 427f1220db8SAlexander V. Chernikov static int 428f1220db8SAlexander V. Chernikov table_show_one(ipfw_xtable_info *i, void *arg) 429f1220db8SAlexander V. Chernikov { 430f1220db8SAlexander V. Chernikov ipfw_obj_header *oh; 431f1220db8SAlexander V. Chernikov 432f1220db8SAlexander V. Chernikov if ((oh = malloc(i->size)) == NULL) 433f1220db8SAlexander V. Chernikov return (ENOMEM); 434f1220db8SAlexander V. Chernikov 435f1220db8SAlexander V. Chernikov if (table_get_list(i, oh) == 0) 436f1220db8SAlexander V. Chernikov table_show_list(oh, 1); 437f1220db8SAlexander V. Chernikov 438f1220db8SAlexander V. Chernikov free(oh); 439f1220db8SAlexander V. Chernikov return (0); 440f1220db8SAlexander V. Chernikov } 441f1220db8SAlexander V. Chernikov 442f1220db8SAlexander V. Chernikov static int 443f1220db8SAlexander V. Chernikov table_flush_one(ipfw_xtable_info *i, void *arg) 444f1220db8SAlexander V. Chernikov { 445f1220db8SAlexander V. Chernikov 446f1220db8SAlexander V. Chernikov return (table_flush(i->tablename, i->set)); 447f1220db8SAlexander V. Chernikov } 448f1220db8SAlexander V. Chernikov 449f1220db8SAlexander V. Chernikov 450f1220db8SAlexander V. Chernikov /* 451f1220db8SAlexander V. Chernikov * Compare table names. 452f1220db8SAlexander V. Chernikov * Honor number comparison. 453f1220db8SAlexander V. Chernikov */ 454f1220db8SAlexander V. Chernikov static int 455f1220db8SAlexander V. Chernikov tablename_cmp(const void *a, const void *b) 456f1220db8SAlexander V. Chernikov { 457f1220db8SAlexander V. Chernikov ipfw_xtable_info *ia, *ib; 458f1220db8SAlexander V. Chernikov int la, lb; 459f1220db8SAlexander V. Chernikov 460f1220db8SAlexander V. Chernikov ia = (ipfw_xtable_info *)a; 461f1220db8SAlexander V. Chernikov ib = (ipfw_xtable_info *)b; 462f1220db8SAlexander V. Chernikov la = strlen(ia->tablename); 463f1220db8SAlexander V. Chernikov lb = strlen(ib->tablename); 464f1220db8SAlexander V. Chernikov 465f1220db8SAlexander V. Chernikov if (la > lb) 466f1220db8SAlexander V. Chernikov return (1); 467f1220db8SAlexander V. Chernikov else if (la < lb) 468f1220db8SAlexander V. Chernikov return (-01); 469f1220db8SAlexander V. Chernikov 470f1220db8SAlexander V. Chernikov return (strcmp(ia->tablename, ib->tablename)); 471f1220db8SAlexander V. Chernikov } 472f1220db8SAlexander V. Chernikov 473f1220db8SAlexander V. Chernikov /* 474f1220db8SAlexander V. Chernikov * Retrieves table list from kernel, 475f1220db8SAlexander V. Chernikov * optionally sorts it and calls requested function for each table. 476f1220db8SAlexander V. Chernikov * Returns 0 on success. 477f1220db8SAlexander V. Chernikov */ 478f1220db8SAlexander V. Chernikov static int 479f1220db8SAlexander V. Chernikov tables_foreach(table_cb_t *f, void *arg, int sort) 480f1220db8SAlexander V. Chernikov { 481f1220db8SAlexander V. Chernikov ipfw_obj_lheader req, *olh; 482f1220db8SAlexander V. Chernikov ipfw_xtable_info *info; 483f1220db8SAlexander V. Chernikov size_t sz; 484f1220db8SAlexander V. Chernikov int i, error; 485f1220db8SAlexander V. Chernikov 486f1220db8SAlexander V. Chernikov memset(&req, 0, sizeof(req)); 487f1220db8SAlexander V. Chernikov sz = sizeof(req); 488f1220db8SAlexander V. Chernikov 489f1220db8SAlexander V. Chernikov req.objtype = IPFW_OBJTYPE_TABLE; 490f1220db8SAlexander V. Chernikov if ((error = do_get3(IP_FW_OBJ_LISTSIZE, &req.opheader, &sz)) != 0) 491f1220db8SAlexander V. Chernikov return (errno); 492f1220db8SAlexander V. Chernikov 493f1220db8SAlexander V. Chernikov sz = req.size; 494f1220db8SAlexander V. Chernikov if ((olh = calloc(1, sz)) == NULL) 495f1220db8SAlexander V. Chernikov return (ENOMEM); 496f1220db8SAlexander V. Chernikov 497f1220db8SAlexander V. Chernikov olh->objtype = IPFW_OBJTYPE_TABLE; 498f1220db8SAlexander V. Chernikov olh->size = sz; 499f1220db8SAlexander V. Chernikov if ((error = do_get3(IP_FW_OBJ_LIST, &olh->opheader, &sz)) != 0) { 500f1220db8SAlexander V. Chernikov free(olh); 501f1220db8SAlexander V. Chernikov return (errno); 502f1220db8SAlexander V. Chernikov } 503f1220db8SAlexander V. Chernikov 504f1220db8SAlexander V. Chernikov if (sort != 0) 505f1220db8SAlexander V. Chernikov qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 506f1220db8SAlexander V. Chernikov 507f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)(olh + 1); 508f1220db8SAlexander V. Chernikov for (i = 0; i < olh->count; i++) { 509f1220db8SAlexander V. Chernikov error = f(info, arg); /* Ignore errors for now */ 510f1220db8SAlexander V. Chernikov info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 511f1220db8SAlexander V. Chernikov } 512f1220db8SAlexander V. Chernikov 513f1220db8SAlexander V. Chernikov free(olh); 514f1220db8SAlexander V. Chernikov 515f1220db8SAlexander V. Chernikov return (0); 516f1220db8SAlexander V. Chernikov } 517f1220db8SAlexander V. Chernikov 518f1220db8SAlexander V. Chernikov /* 519f1220db8SAlexander V. Chernikov * Retrieves all entries for given table @i in 520f1220db8SAlexander V. Chernikov * eXtended format, returning pointer vi @ooh. 521f1220db8SAlexander V. Chernikov * 522f1220db8SAlexander V. Chernikov * Returns 0 on success. 523f1220db8SAlexander V. Chernikov */ 524f1220db8SAlexander V. Chernikov static int 525f1220db8SAlexander V. Chernikov table_get_list(ipfw_xtable_info *i, ipfw_obj_header *oh) 526f1220db8SAlexander V. Chernikov { 527f1220db8SAlexander V. Chernikov size_t sz; 528f1220db8SAlexander V. Chernikov int error; 529f1220db8SAlexander V. Chernikov 530f1220db8SAlexander V. Chernikov table_fill_objheader(oh, i); 531f1220db8SAlexander V. Chernikov sz = i->size; 532f1220db8SAlexander V. Chernikov 533f1220db8SAlexander V. Chernikov if ((error = do_get3(IP_FW_OBJ_DUMP, &oh->opheader, &sz)) != 0) 534f1220db8SAlexander V. Chernikov return (errno); 535f1220db8SAlexander V. Chernikov 536f1220db8SAlexander V. Chernikov return (0); 537f1220db8SAlexander V. Chernikov } 538f1220db8SAlexander V. Chernikov 539f1220db8SAlexander V. Chernikov /* 540f1220db8SAlexander V. Chernikov * Shows all entries from @oh in human-readable format 541f1220db8SAlexander V. Chernikov */ 542f1220db8SAlexander V. Chernikov static void 543f1220db8SAlexander V. Chernikov table_show_list(ipfw_obj_header *oh, int need_header) 544f1220db8SAlexander V. Chernikov { 545f1220db8SAlexander V. Chernikov ipfw_table_xentry *xent; 546f1220db8SAlexander V. Chernikov uint32_t count, tval; 547f1220db8SAlexander V. Chernikov char tbuf[128]; 548f1220db8SAlexander V. Chernikov struct in6_addr *addr6; 549f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 550f1220db8SAlexander V. Chernikov 551f1220db8SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 552f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)(i + 1); 553f1220db8SAlexander V. Chernikov 554f1220db8SAlexander V. Chernikov if (need_header) 555f1220db8SAlexander V. Chernikov printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 556f1220db8SAlexander V. Chernikov 557f1220db8SAlexander V. Chernikov count = i->count; 558f1220db8SAlexander V. Chernikov while (count > 0) { 559f1220db8SAlexander V. Chernikov switch (i->type) { 560f1220db8SAlexander V. Chernikov case IPFW_TABLE_CIDR: 561f1220db8SAlexander V. Chernikov /* IPv4 or IPv6 prefixes */ 562f1220db8SAlexander V. Chernikov tval = xent->value; 563f1220db8SAlexander V. Chernikov addr6 = &xent->k.addr6; 564f1220db8SAlexander V. Chernikov 565f1220db8SAlexander V. Chernikov 566f1220db8SAlexander V. Chernikov if ((xent->flags & IPFW_TCF_INET) != 0) { 567f1220db8SAlexander V. Chernikov /* IPv4 address */ 568f1220db8SAlexander V. Chernikov inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, 569f1220db8SAlexander V. Chernikov sizeof(tbuf)); 570f1220db8SAlexander V. Chernikov } else { 571f1220db8SAlexander V. Chernikov /* IPv6 address */ 572f1220db8SAlexander V. Chernikov inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf)); 573f1220db8SAlexander V. Chernikov } 574f1220db8SAlexander V. Chernikov 575f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 576f1220db8SAlexander V. Chernikov tval = htonl(tval); 577f1220db8SAlexander V. Chernikov printf("%s/%u %s\n", tbuf, xent->masklen, 578f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 579f1220db8SAlexander V. Chernikov } else 580f1220db8SAlexander V. Chernikov printf("%s/%u %u\n", tbuf, xent->masklen, tval); 581f1220db8SAlexander V. Chernikov break; 582f1220db8SAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 583f1220db8SAlexander V. Chernikov /* Interface names */ 584f1220db8SAlexander V. Chernikov tval = xent->value; 585f1220db8SAlexander V. Chernikov if (co.do_value_as_ip) { 586f1220db8SAlexander V. Chernikov tval = htonl(tval); 587f1220db8SAlexander V. Chernikov printf("%s %s\n", xent->k.iface, 588f1220db8SAlexander V. Chernikov inet_ntoa(*(struct in_addr *)&tval)); 589f1220db8SAlexander V. Chernikov } else 590f1220db8SAlexander V. Chernikov printf("%s %u\n", xent->k.iface, tval); 591f1220db8SAlexander V. Chernikov } 592f1220db8SAlexander V. Chernikov 593f1220db8SAlexander V. Chernikov xent = (ipfw_table_xentry *)((caddr_t)xent + xent->len); 594f1220db8SAlexander V. Chernikov count--; 595f1220db8SAlexander V. Chernikov } 596f1220db8SAlexander V. Chernikov } 597f1220db8SAlexander V. Chernikov 598