15c04f73eSAndrey V. Elsukov /*- 25c04f73eSAndrey V. Elsukov * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 35c04f73eSAndrey V. Elsukov * 45c04f73eSAndrey V. Elsukov * Copyright (c) 2019 Yandex LLC 55c04f73eSAndrey V. Elsukov * Copyright (c) 2019 Andrey V. Elsukov <ae@FreeBSD.org> 65c04f73eSAndrey V. Elsukov * Copyright (c) 2019 Boris N. Lytochkin <lytboris@gmail.com> 75c04f73eSAndrey V. Elsukov * 85c04f73eSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 95c04f73eSAndrey V. Elsukov * modification, are permitted provided that the following conditions 105c04f73eSAndrey V. Elsukov * are met: 115c04f73eSAndrey V. Elsukov * 125c04f73eSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 135c04f73eSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 145c04f73eSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 155c04f73eSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 165c04f73eSAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 175c04f73eSAndrey V. Elsukov * 185c04f73eSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 195c04f73eSAndrey V. Elsukov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 205c04f73eSAndrey V. Elsukov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 215c04f73eSAndrey V. Elsukov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 225c04f73eSAndrey V. Elsukov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 235c04f73eSAndrey V. Elsukov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 245c04f73eSAndrey V. Elsukov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 255c04f73eSAndrey V. Elsukov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 265c04f73eSAndrey V. Elsukov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 275c04f73eSAndrey V. Elsukov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 285c04f73eSAndrey V. Elsukov */ 295c04f73eSAndrey V. Elsukov 305c04f73eSAndrey V. Elsukov #include <sys/cdefs.h> 315c04f73eSAndrey V. Elsukov __FBSDID("$FreeBSD$"); 325c04f73eSAndrey V. Elsukov 335c04f73eSAndrey V. Elsukov #include <sys/types.h> 345c04f73eSAndrey V. Elsukov #include <sys/socket.h> 355c04f73eSAndrey V. Elsukov 365c04f73eSAndrey V. Elsukov #include "ipfw2.h" 375c04f73eSAndrey V. Elsukov 385c04f73eSAndrey V. Elsukov #include <ctype.h> 395c04f73eSAndrey V. Elsukov #include <err.h> 405c04f73eSAndrey V. Elsukov #include <errno.h> 415c04f73eSAndrey V. Elsukov #include <inttypes.h> 425c04f73eSAndrey V. Elsukov #include <netdb.h> 435c04f73eSAndrey V. Elsukov #include <stdio.h> 445c04f73eSAndrey V. Elsukov #include <stdlib.h> 455c04f73eSAndrey V. Elsukov #include <string.h> 465c04f73eSAndrey V. Elsukov #include <sysexits.h> 475c04f73eSAndrey V. Elsukov 485c04f73eSAndrey V. Elsukov #include <net/if.h> 495c04f73eSAndrey V. Elsukov #include <netinet/in.h> 505c04f73eSAndrey V. Elsukov #include <netinet/ip_fw.h> 515c04f73eSAndrey V. Elsukov #include <netinet6/ip_fw_nat64.h> 525c04f73eSAndrey V. Elsukov #include <arpa/inet.h> 535c04f73eSAndrey V. Elsukov 545c04f73eSAndrey V. Elsukov typedef int (nat64clat_cb_t)(ipfw_nat64clat_cfg *i, const char *name, 555c04f73eSAndrey V. Elsukov uint8_t set); 565c04f73eSAndrey V. Elsukov static int nat64clat_foreach(nat64clat_cb_t *f, const char *name, uint8_t set, 575c04f73eSAndrey V. Elsukov int sort); 585c04f73eSAndrey V. Elsukov 595c04f73eSAndrey V. Elsukov static void nat64clat_create(const char *name, uint8_t set, int ac, char **av); 605c04f73eSAndrey V. Elsukov static void nat64clat_config(const char *name, uint8_t set, int ac, char **av); 615c04f73eSAndrey V. Elsukov static void nat64clat_destroy(const char *name, uint8_t set); 625c04f73eSAndrey V. Elsukov static void nat64clat_stats(const char *name, uint8_t set); 635c04f73eSAndrey V. Elsukov static void nat64clat_reset_stats(const char *name, uint8_t set); 645c04f73eSAndrey V. Elsukov static int nat64clat_show_cb(ipfw_nat64clat_cfg *cfg, const char *name, 655c04f73eSAndrey V. Elsukov uint8_t set); 665c04f73eSAndrey V. Elsukov static int nat64clat_destroy_cb(ipfw_nat64clat_cfg *cfg, const char *name, 675c04f73eSAndrey V. Elsukov uint8_t set); 685c04f73eSAndrey V. Elsukov 695c04f73eSAndrey V. Elsukov static struct _s_x nat64cmds[] = { 705c04f73eSAndrey V. Elsukov { "create", TOK_CREATE }, 715c04f73eSAndrey V. Elsukov { "config", TOK_CONFIG }, 725c04f73eSAndrey V. Elsukov { "destroy", TOK_DESTROY }, 735c04f73eSAndrey V. Elsukov { "list", TOK_LIST }, 745c04f73eSAndrey V. Elsukov { "show", TOK_LIST }, 755c04f73eSAndrey V. Elsukov { "stats", TOK_STATS }, 765c04f73eSAndrey V. Elsukov { NULL, 0 } 775c04f73eSAndrey V. Elsukov }; 785c04f73eSAndrey V. Elsukov 795c04f73eSAndrey V. Elsukov static struct _s_x nat64statscmds[] = { 805c04f73eSAndrey V. Elsukov { "reset", TOK_RESET }, 815c04f73eSAndrey V. Elsukov { NULL, 0 } 825c04f73eSAndrey V. Elsukov }; 835c04f73eSAndrey V. Elsukov 845c04f73eSAndrey V. Elsukov /* 855c04f73eSAndrey V. Elsukov * This one handles all nat64clat-related commands 865c04f73eSAndrey V. Elsukov * ipfw [set N] nat64clat NAME {create | config} ... 875c04f73eSAndrey V. Elsukov * ipfw [set N] nat64clat NAME stats [reset] 885c04f73eSAndrey V. Elsukov * ipfw [set N] nat64clat {NAME | all} destroy 895c04f73eSAndrey V. Elsukov * ipfw [set N] nat64clat {NAME | all} {list | show} 905c04f73eSAndrey V. Elsukov */ 915c04f73eSAndrey V. Elsukov #define nat64clat_check_name table_check_name 925c04f73eSAndrey V. Elsukov void 935c04f73eSAndrey V. Elsukov ipfw_nat64clat_handler(int ac, char *av[]) 945c04f73eSAndrey V. Elsukov { 955c04f73eSAndrey V. Elsukov const char *name; 965c04f73eSAndrey V. Elsukov int tcmd; 975c04f73eSAndrey V. Elsukov uint8_t set; 985c04f73eSAndrey V. Elsukov 9956707beeSMark Johnston if (g_co.use_set != 0) 10056707beeSMark Johnston set = g_co.use_set - 1; 1015c04f73eSAndrey V. Elsukov else 1025c04f73eSAndrey V. Elsukov set = 0; 1035c04f73eSAndrey V. Elsukov ac--; av++; 1045c04f73eSAndrey V. Elsukov 1055c04f73eSAndrey V. Elsukov NEED1("nat64clat needs instance name"); 1065c04f73eSAndrey V. Elsukov name = *av; 1075c04f73eSAndrey V. Elsukov if (nat64clat_check_name(name) != 0) { 1085c04f73eSAndrey V. Elsukov if (strcmp(name, "all") == 0) 1095c04f73eSAndrey V. Elsukov name = NULL; 1105c04f73eSAndrey V. Elsukov else 1115c04f73eSAndrey V. Elsukov errx(EX_USAGE, "nat64clat instance name %s is invalid", 1125c04f73eSAndrey V. Elsukov name); 1135c04f73eSAndrey V. Elsukov } 1145c04f73eSAndrey V. Elsukov ac--; av++; 1155c04f73eSAndrey V. Elsukov NEED1("nat64clat needs command"); 1165c04f73eSAndrey V. Elsukov 1175c04f73eSAndrey V. Elsukov tcmd = get_token(nat64cmds, *av, "nat64clat command"); 1185c04f73eSAndrey V. Elsukov if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST) 1195c04f73eSAndrey V. Elsukov errx(EX_USAGE, "nat64clat instance name required"); 1205c04f73eSAndrey V. Elsukov switch (tcmd) { 1215c04f73eSAndrey V. Elsukov case TOK_CREATE: 1225c04f73eSAndrey V. Elsukov ac--; av++; 1235c04f73eSAndrey V. Elsukov nat64clat_create(name, set, ac, av); 1245c04f73eSAndrey V. Elsukov break; 1255c04f73eSAndrey V. Elsukov case TOK_CONFIG: 1265c04f73eSAndrey V. Elsukov ac--; av++; 1275c04f73eSAndrey V. Elsukov nat64clat_config(name, set, ac, av); 1285c04f73eSAndrey V. Elsukov break; 1295c04f73eSAndrey V. Elsukov case TOK_LIST: 1305c04f73eSAndrey V. Elsukov nat64clat_foreach(nat64clat_show_cb, name, set, 1); 1315c04f73eSAndrey V. Elsukov break; 1325c04f73eSAndrey V. Elsukov case TOK_DESTROY: 1335c04f73eSAndrey V. Elsukov if (name == NULL) 1345c04f73eSAndrey V. Elsukov nat64clat_foreach(nat64clat_destroy_cb, NULL, set, 0); 1355c04f73eSAndrey V. Elsukov else 1365c04f73eSAndrey V. Elsukov nat64clat_destroy(name, set); 1375c04f73eSAndrey V. Elsukov break; 1385c04f73eSAndrey V. Elsukov case TOK_STATS: 1395c04f73eSAndrey V. Elsukov ac--; av++; 1405c04f73eSAndrey V. Elsukov if (ac == 0) { 1415c04f73eSAndrey V. Elsukov nat64clat_stats(name, set); 1425c04f73eSAndrey V. Elsukov break; 1435c04f73eSAndrey V. Elsukov } 1445c04f73eSAndrey V. Elsukov tcmd = get_token(nat64statscmds, *av, "stats command"); 1455c04f73eSAndrey V. Elsukov if (tcmd == TOK_RESET) 1465c04f73eSAndrey V. Elsukov nat64clat_reset_stats(name, set); 1475c04f73eSAndrey V. Elsukov } 1485c04f73eSAndrey V. Elsukov } 1495c04f73eSAndrey V. Elsukov 1505c04f73eSAndrey V. Elsukov 1515c04f73eSAndrey V. Elsukov static void 1525c04f73eSAndrey V. Elsukov nat64clat_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set) 1535c04f73eSAndrey V. Elsukov { 1545c04f73eSAndrey V. Elsukov 1555c04f73eSAndrey V. Elsukov ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */ 1565c04f73eSAndrey V. Elsukov ntlv->head.length = sizeof(ipfw_obj_ntlv); 1575c04f73eSAndrey V. Elsukov ntlv->idx = 1; 1585c04f73eSAndrey V. Elsukov ntlv->set = set; 1595c04f73eSAndrey V. Elsukov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 1605c04f73eSAndrey V. Elsukov } 1615c04f73eSAndrey V. Elsukov 1625c04f73eSAndrey V. Elsukov static struct _s_x nat64newcmds[] = { 1635c04f73eSAndrey V. Elsukov { "plat_prefix", TOK_PLAT_PREFIX }, 1645c04f73eSAndrey V. Elsukov { "clat_prefix", TOK_CLAT_PREFIX }, 1655c04f73eSAndrey V. Elsukov { "log", TOK_LOG }, 1665c04f73eSAndrey V. Elsukov { "-log", TOK_LOGOFF }, 1675c04f73eSAndrey V. Elsukov { "allow_private", TOK_PRIVATE }, 1685c04f73eSAndrey V. Elsukov { "-allow_private", TOK_PRIVATEOFF }, 1695c04f73eSAndrey V. Elsukov { NULL, 0 } 1705c04f73eSAndrey V. Elsukov }; 1715c04f73eSAndrey V. Elsukov 1725c04f73eSAndrey V. Elsukov /* 1735c04f73eSAndrey V. Elsukov * Creates new nat64clat instance 1745c04f73eSAndrey V. Elsukov * ipfw nat64clat <NAME> create clat_prefix <prefix> plat_prefix <prefix> 1755c04f73eSAndrey V. Elsukov * Request: [ ipfw_obj_lheader ipfw_nat64clat_cfg ] 1765c04f73eSAndrey V. Elsukov */ 1775c04f73eSAndrey V. Elsukov #define NAT64CLAT_HAS_CLAT_PREFIX 0x01 1785c04f73eSAndrey V. Elsukov #define NAT64CLAT_HAS_PLAT_PREFIX 0x02 1795c04f73eSAndrey V. Elsukov static void 1805c04f73eSAndrey V. Elsukov nat64clat_create(const char *name, uint8_t set, int ac, char *av[]) 1815c04f73eSAndrey V. Elsukov { 1825c04f73eSAndrey V. Elsukov char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64clat_cfg)]; 1835c04f73eSAndrey V. Elsukov ipfw_nat64clat_cfg *cfg; 1845c04f73eSAndrey V. Elsukov ipfw_obj_lheader *olh; 1855c04f73eSAndrey V. Elsukov int tcmd, flags; 1865c04f73eSAndrey V. Elsukov char *p; 1875c04f73eSAndrey V. Elsukov struct in6_addr prefix; 1885c04f73eSAndrey V. Elsukov uint8_t plen; 1895c04f73eSAndrey V. Elsukov 1905c04f73eSAndrey V. Elsukov memset(buf, 0, sizeof(buf)); 1915c04f73eSAndrey V. Elsukov olh = (ipfw_obj_lheader *)buf; 1925c04f73eSAndrey V. Elsukov cfg = (ipfw_nat64clat_cfg *)(olh + 1); 1935c04f73eSAndrey V. Elsukov 1945c04f73eSAndrey V. Elsukov /* Some reasonable defaults */ 1955c04f73eSAndrey V. Elsukov inet_pton(AF_INET6, "64:ff9b::", &cfg->plat_prefix); 1965c04f73eSAndrey V. Elsukov cfg->plat_plen = 96; 1975c04f73eSAndrey V. Elsukov cfg->set = set; 1985c04f73eSAndrey V. Elsukov flags = NAT64CLAT_HAS_PLAT_PREFIX; 1995c04f73eSAndrey V. Elsukov while (ac > 0) { 2005c04f73eSAndrey V. Elsukov tcmd = get_token(nat64newcmds, *av, "option"); 2015c04f73eSAndrey V. Elsukov ac--; av++; 2025c04f73eSAndrey V. Elsukov 2035c04f73eSAndrey V. Elsukov switch (tcmd) { 2045c04f73eSAndrey V. Elsukov case TOK_PLAT_PREFIX: 2055c04f73eSAndrey V. Elsukov case TOK_CLAT_PREFIX: 2065c04f73eSAndrey V. Elsukov if (tcmd == TOK_PLAT_PREFIX) { 2075c04f73eSAndrey V. Elsukov NEED1("IPv6 plat_prefix required"); 2085c04f73eSAndrey V. Elsukov } else { 2095c04f73eSAndrey V. Elsukov NEED1("IPv6 clat_prefix required"); 2105c04f73eSAndrey V. Elsukov } 2115c04f73eSAndrey V. Elsukov 2125c04f73eSAndrey V. Elsukov if ((p = strchr(*av, '/')) != NULL) 2135c04f73eSAndrey V. Elsukov *p++ = '\0'; 2145c04f73eSAndrey V. Elsukov if (inet_pton(AF_INET6, *av, &prefix) != 1) 2155c04f73eSAndrey V. Elsukov errx(EX_USAGE, 2165c04f73eSAndrey V. Elsukov "Bad prefix: %s", *av); 2175c04f73eSAndrey V. Elsukov plen = strtol(p, NULL, 10); 2185c04f73eSAndrey V. Elsukov if (ipfw_check_nat64prefix(&prefix, plen) != 0) 2195c04f73eSAndrey V. Elsukov errx(EX_USAGE, 2205c04f73eSAndrey V. Elsukov "Bad prefix length: %s", p); 2215c04f73eSAndrey V. Elsukov if (tcmd == TOK_PLAT_PREFIX) { 2225c04f73eSAndrey V. Elsukov flags |= NAT64CLAT_HAS_PLAT_PREFIX; 2235c04f73eSAndrey V. Elsukov cfg->plat_prefix = prefix; 2245c04f73eSAndrey V. Elsukov cfg->plat_plen = plen; 2255c04f73eSAndrey V. Elsukov } else { 2265c04f73eSAndrey V. Elsukov flags |= NAT64CLAT_HAS_CLAT_PREFIX; 2275c04f73eSAndrey V. Elsukov cfg->clat_prefix = prefix; 2285c04f73eSAndrey V. Elsukov cfg->clat_plen = plen; 2295c04f73eSAndrey V. Elsukov } 2305c04f73eSAndrey V. Elsukov ac--; av++; 2315c04f73eSAndrey V. Elsukov break; 2325c04f73eSAndrey V. Elsukov case TOK_LOG: 2335c04f73eSAndrey V. Elsukov cfg->flags |= NAT64_LOG; 2345c04f73eSAndrey V. Elsukov break; 2355c04f73eSAndrey V. Elsukov case TOK_LOGOFF: 2365c04f73eSAndrey V. Elsukov cfg->flags &= ~NAT64_LOG; 2375c04f73eSAndrey V. Elsukov break; 2385c04f73eSAndrey V. Elsukov case TOK_PRIVATE: 2395c04f73eSAndrey V. Elsukov cfg->flags |= NAT64_ALLOW_PRIVATE; 2405c04f73eSAndrey V. Elsukov break; 2415c04f73eSAndrey V. Elsukov case TOK_PRIVATEOFF: 2425c04f73eSAndrey V. Elsukov cfg->flags &= ~NAT64_ALLOW_PRIVATE; 2435c04f73eSAndrey V. Elsukov break; 2445c04f73eSAndrey V. Elsukov } 2455c04f73eSAndrey V. Elsukov } 2465c04f73eSAndrey V. Elsukov 2475c04f73eSAndrey V. Elsukov /* Check validness */ 2485c04f73eSAndrey V. Elsukov if ((flags & NAT64CLAT_HAS_PLAT_PREFIX) != NAT64CLAT_HAS_PLAT_PREFIX) 2495c04f73eSAndrey V. Elsukov errx(EX_USAGE, "plat_prefix required"); 2505c04f73eSAndrey V. Elsukov if ((flags & NAT64CLAT_HAS_CLAT_PREFIX) != NAT64CLAT_HAS_CLAT_PREFIX) 2515c04f73eSAndrey V. Elsukov errx(EX_USAGE, "clat_prefix required"); 2525c04f73eSAndrey V. Elsukov 2535c04f73eSAndrey V. Elsukov olh->count = 1; 2545c04f73eSAndrey V. Elsukov olh->objsize = sizeof(*cfg); 2555c04f73eSAndrey V. Elsukov olh->size = sizeof(buf); 2565c04f73eSAndrey V. Elsukov strlcpy(cfg->name, name, sizeof(cfg->name)); 2575c04f73eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64CLAT_CREATE, &olh->opheader, sizeof(buf)) != 0) 2585c04f73eSAndrey V. Elsukov err(EX_OSERR, "nat64clat instance creation failed"); 2595c04f73eSAndrey V. Elsukov } 2605c04f73eSAndrey V. Elsukov 2615c04f73eSAndrey V. Elsukov /* 2625c04f73eSAndrey V. Elsukov * Configures existing nat64clat instance 2635c04f73eSAndrey V. Elsukov * ipfw nat64clat <NAME> config <options> 2645c04f73eSAndrey V. Elsukov * Request: [ ipfw_obj_header ipfw_nat64clat_cfg ] 2655c04f73eSAndrey V. Elsukov */ 2665c04f73eSAndrey V. Elsukov static void 2675c04f73eSAndrey V. Elsukov nat64clat_config(const char *name, uint8_t set, int ac, char **av) 2685c04f73eSAndrey V. Elsukov { 2695c04f73eSAndrey V. Elsukov char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64clat_cfg)]; 2705c04f73eSAndrey V. Elsukov ipfw_nat64clat_cfg *cfg; 2715c04f73eSAndrey V. Elsukov ipfw_obj_header *oh; 2725c04f73eSAndrey V. Elsukov char *opt; 2735c04f73eSAndrey V. Elsukov char *p; 2745c04f73eSAndrey V. Elsukov size_t sz; 2755c04f73eSAndrey V. Elsukov int tcmd; 2765c04f73eSAndrey V. Elsukov struct in6_addr prefix; 2775c04f73eSAndrey V. Elsukov uint8_t plen; 2785c04f73eSAndrey V. Elsukov 2795c04f73eSAndrey V. Elsukov if (ac == 0) 2805c04f73eSAndrey V. Elsukov errx(EX_USAGE, "config options required"); 2815c04f73eSAndrey V. Elsukov memset(&buf, 0, sizeof(buf)); 2825c04f73eSAndrey V. Elsukov oh = (ipfw_obj_header *)buf; 2835c04f73eSAndrey V. Elsukov cfg = (ipfw_nat64clat_cfg *)(oh + 1); 2845c04f73eSAndrey V. Elsukov sz = sizeof(buf); 2855c04f73eSAndrey V. Elsukov 2865c04f73eSAndrey V. Elsukov nat64clat_fill_ntlv(&oh->ntlv, name, set); 2875c04f73eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, &sz) != 0) 2885c04f73eSAndrey V. Elsukov err(EX_OSERR, "failed to get config for instance %s", name); 2895c04f73eSAndrey V. Elsukov 2905c04f73eSAndrey V. Elsukov while (ac > 0) { 2915c04f73eSAndrey V. Elsukov tcmd = get_token(nat64newcmds, *av, "option"); 2925c04f73eSAndrey V. Elsukov opt = *av; 2935c04f73eSAndrey V. Elsukov ac--; av++; 2945c04f73eSAndrey V. Elsukov 2955c04f73eSAndrey V. Elsukov switch (tcmd) { 2965c04f73eSAndrey V. Elsukov case TOK_PLAT_PREFIX: 2975c04f73eSAndrey V. Elsukov case TOK_CLAT_PREFIX: 2985c04f73eSAndrey V. Elsukov if (tcmd == TOK_PLAT_PREFIX) { 2995c04f73eSAndrey V. Elsukov NEED1("IPv6 plat_prefix required"); 3005c04f73eSAndrey V. Elsukov } else { 3015c04f73eSAndrey V. Elsukov NEED1("IPv6 clat_prefix required"); 3025c04f73eSAndrey V. Elsukov } 3035c04f73eSAndrey V. Elsukov 3045c04f73eSAndrey V. Elsukov if ((p = strchr(*av, '/')) != NULL) 3055c04f73eSAndrey V. Elsukov *p++ = '\0'; 3062403d477SAndrey V. Elsukov else 3072403d477SAndrey V. Elsukov errx(EX_USAGE, 3082403d477SAndrey V. Elsukov "Prefix length required: %s", *av); 3095c04f73eSAndrey V. Elsukov if (inet_pton(AF_INET6, *av, &prefix) != 1) 3105c04f73eSAndrey V. Elsukov errx(EX_USAGE, 3115c04f73eSAndrey V. Elsukov "Bad prefix: %s", *av); 3125c04f73eSAndrey V. Elsukov plen = strtol(p, NULL, 10); 3135c04f73eSAndrey V. Elsukov if (ipfw_check_nat64prefix(&prefix, plen) != 0) 3145c04f73eSAndrey V. Elsukov errx(EX_USAGE, 3155c04f73eSAndrey V. Elsukov "Bad prefix length: %s", p); 3165c04f73eSAndrey V. Elsukov if (tcmd == TOK_PLAT_PREFIX) { 3175c04f73eSAndrey V. Elsukov cfg->plat_prefix = prefix; 3185c04f73eSAndrey V. Elsukov cfg->plat_plen = plen; 3195c04f73eSAndrey V. Elsukov } else { 3205c04f73eSAndrey V. Elsukov cfg->clat_prefix = prefix; 3215c04f73eSAndrey V. Elsukov cfg->clat_plen = plen; 3225c04f73eSAndrey V. Elsukov } 3235c04f73eSAndrey V. Elsukov ac--; av++; 3245c04f73eSAndrey V. Elsukov break; 3255c04f73eSAndrey V. Elsukov case TOK_LOG: 3265c04f73eSAndrey V. Elsukov cfg->flags |= NAT64_LOG; 3275c04f73eSAndrey V. Elsukov break; 3285c04f73eSAndrey V. Elsukov case TOK_LOGOFF: 3295c04f73eSAndrey V. Elsukov cfg->flags &= ~NAT64_LOG; 3305c04f73eSAndrey V. Elsukov break; 3315c04f73eSAndrey V. Elsukov case TOK_PRIVATE: 3325c04f73eSAndrey V. Elsukov cfg->flags |= NAT64_ALLOW_PRIVATE; 3335c04f73eSAndrey V. Elsukov break; 3345c04f73eSAndrey V. Elsukov case TOK_PRIVATEOFF: 3355c04f73eSAndrey V. Elsukov cfg->flags &= ~NAT64_ALLOW_PRIVATE; 3365c04f73eSAndrey V. Elsukov break; 3375c04f73eSAndrey V. Elsukov default: 3385c04f73eSAndrey V. Elsukov errx(EX_USAGE, "Can't change %s option", opt); 3395c04f73eSAndrey V. Elsukov } 3405c04f73eSAndrey V. Elsukov } 3415c04f73eSAndrey V. Elsukov 3425c04f73eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, sizeof(buf)) != 0) 3435c04f73eSAndrey V. Elsukov err(EX_OSERR, "nat64clat instance configuration failed"); 3445c04f73eSAndrey V. Elsukov } 3455c04f73eSAndrey V. Elsukov 3465c04f73eSAndrey V. Elsukov /* 3475c04f73eSAndrey V. Elsukov * Destroys nat64clat instance. 3485c04f73eSAndrey V. Elsukov * Request: [ ipfw_obj_header ] 3495c04f73eSAndrey V. Elsukov */ 3505c04f73eSAndrey V. Elsukov static void 3515c04f73eSAndrey V. Elsukov nat64clat_destroy(const char *name, uint8_t set) 3525c04f73eSAndrey V. Elsukov { 3535c04f73eSAndrey V. Elsukov ipfw_obj_header oh; 3545c04f73eSAndrey V. Elsukov 3555c04f73eSAndrey V. Elsukov memset(&oh, 0, sizeof(oh)); 3565c04f73eSAndrey V. Elsukov nat64clat_fill_ntlv(&oh.ntlv, name, set); 3575c04f73eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64CLAT_DESTROY, &oh.opheader, sizeof(oh)) != 0) 3585c04f73eSAndrey V. Elsukov err(EX_OSERR, "failed to destroy nat instance %s", name); 3595c04f73eSAndrey V. Elsukov } 3605c04f73eSAndrey V. Elsukov 3615c04f73eSAndrey V. Elsukov /* 3625c04f73eSAndrey V. Elsukov * Get nat64clat instance statistics. 3635c04f73eSAndrey V. Elsukov * Request: [ ipfw_obj_header ] 3645c04f73eSAndrey V. Elsukov * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ] 3655c04f73eSAndrey V. Elsukov */ 3665c04f73eSAndrey V. Elsukov static int 3675c04f73eSAndrey V. Elsukov nat64clat_get_stats(const char *name, uint8_t set, 3685c04f73eSAndrey V. Elsukov struct ipfw_nat64clat_stats *stats) 3695c04f73eSAndrey V. Elsukov { 3705c04f73eSAndrey V. Elsukov ipfw_obj_header *oh; 3715c04f73eSAndrey V. Elsukov ipfw_obj_ctlv *oc; 3725c04f73eSAndrey V. Elsukov size_t sz; 3735c04f73eSAndrey V. Elsukov 3745c04f73eSAndrey V. Elsukov sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats); 3755c04f73eSAndrey V. Elsukov oh = calloc(1, sz); 3765c04f73eSAndrey V. Elsukov nat64clat_fill_ntlv(&oh->ntlv, name, set); 3775c04f73eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64CLAT_STATS, &oh->opheader, &sz) == 0) { 3785c04f73eSAndrey V. Elsukov oc = (ipfw_obj_ctlv *)(oh + 1); 3795c04f73eSAndrey V. Elsukov memcpy(stats, oc + 1, sizeof(*stats)); 3805c04f73eSAndrey V. Elsukov free(oh); 3815c04f73eSAndrey V. Elsukov return (0); 3825c04f73eSAndrey V. Elsukov } 3835c04f73eSAndrey V. Elsukov free(oh); 3845c04f73eSAndrey V. Elsukov return (-1); 3855c04f73eSAndrey V. Elsukov } 3865c04f73eSAndrey V. Elsukov 3875c04f73eSAndrey V. Elsukov static void 3885c04f73eSAndrey V. Elsukov nat64clat_stats(const char *name, uint8_t set) 3895c04f73eSAndrey V. Elsukov { 3905c04f73eSAndrey V. Elsukov struct ipfw_nat64clat_stats stats; 3915c04f73eSAndrey V. Elsukov 3925c04f73eSAndrey V. Elsukov if (nat64clat_get_stats(name, set, &stats) != 0) 3935c04f73eSAndrey V. Elsukov err(EX_OSERR, "Error retrieving stats"); 3945c04f73eSAndrey V. Elsukov 39556707beeSMark Johnston if (g_co.use_set != 0 || set != 0) 3965c04f73eSAndrey V. Elsukov printf("set %u ", set); 3975c04f73eSAndrey V. Elsukov printf("nat64clat %s\n", name); 3985c04f73eSAndrey V. Elsukov 3995c04f73eSAndrey V. Elsukov printf("\t%ju packets translated from IPv6 to IPv4\n", 4005c04f73eSAndrey V. Elsukov (uintmax_t)stats.opcnt64); 4015c04f73eSAndrey V. Elsukov printf("\t%ju packets translated from IPv4 to IPv6\n", 4025c04f73eSAndrey V. Elsukov (uintmax_t)stats.opcnt46); 4035c04f73eSAndrey V. Elsukov printf("\t%ju IPv6 fragments created\n", 4045c04f73eSAndrey V. Elsukov (uintmax_t)stats.ofrags); 4055c04f73eSAndrey V. Elsukov printf("\t%ju IPv4 fragments received\n", 4065c04f73eSAndrey V. Elsukov (uintmax_t)stats.ifrags); 4075c04f73eSAndrey V. Elsukov printf("\t%ju output packets dropped due to no bufs, etc.\n", 4085c04f73eSAndrey V. Elsukov (uintmax_t)stats.oerrors); 4095c04f73eSAndrey V. Elsukov printf("\t%ju output packets discarded due to no IPv4 route\n", 4105c04f73eSAndrey V. Elsukov (uintmax_t)stats.noroute4); 4115c04f73eSAndrey V. Elsukov printf("\t%ju output packets discarded due to no IPv6 route\n", 4125c04f73eSAndrey V. Elsukov (uintmax_t)stats.noroute6); 4135c04f73eSAndrey V. Elsukov printf("\t%ju packets discarded due to unsupported protocol\n", 4145c04f73eSAndrey V. Elsukov (uintmax_t)stats.noproto); 4155c04f73eSAndrey V. Elsukov printf("\t%ju packets discarded due to memory allocation problems\n", 4165c04f73eSAndrey V. Elsukov (uintmax_t)stats.nomem); 4175c04f73eSAndrey V. Elsukov printf("\t%ju packets discarded due to some errors\n", 4185c04f73eSAndrey V. Elsukov (uintmax_t)stats.dropped); 4195c04f73eSAndrey V. Elsukov } 4205c04f73eSAndrey V. Elsukov 4215c04f73eSAndrey V. Elsukov /* 4225c04f73eSAndrey V. Elsukov * Reset nat64clat instance statistics specified by @oh->ntlv. 4235c04f73eSAndrey V. Elsukov * Request: [ ipfw_obj_header ] 4245c04f73eSAndrey V. Elsukov */ 4255c04f73eSAndrey V. Elsukov static void 4265c04f73eSAndrey V. Elsukov nat64clat_reset_stats(const char *name, uint8_t set) 4275c04f73eSAndrey V. Elsukov { 4285c04f73eSAndrey V. Elsukov ipfw_obj_header oh; 4295c04f73eSAndrey V. Elsukov 4305c04f73eSAndrey V. Elsukov memset(&oh, 0, sizeof(oh)); 4315c04f73eSAndrey V. Elsukov nat64clat_fill_ntlv(&oh.ntlv, name, set); 4325c04f73eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64CLAT_RESET_STATS, &oh.opheader, sizeof(oh)) != 0) 4335c04f73eSAndrey V. Elsukov err(EX_OSERR, "failed to reset stats for instance %s", name); 4345c04f73eSAndrey V. Elsukov } 4355c04f73eSAndrey V. Elsukov 4365c04f73eSAndrey V. Elsukov static int 4375c04f73eSAndrey V. Elsukov nat64clat_show_cb(ipfw_nat64clat_cfg *cfg, const char *name, uint8_t set) 4385c04f73eSAndrey V. Elsukov { 4395c04f73eSAndrey V. Elsukov char plat_buf[INET6_ADDRSTRLEN], clat_buf[INET6_ADDRSTRLEN]; 4405c04f73eSAndrey V. Elsukov 4415c04f73eSAndrey V. Elsukov if (name != NULL && strcmp(cfg->name, name) != 0) 4425c04f73eSAndrey V. Elsukov return (ESRCH); 4435c04f73eSAndrey V. Elsukov 44456707beeSMark Johnston if (g_co.use_set != 0 && cfg->set != set) 4455c04f73eSAndrey V. Elsukov return (ESRCH); 4465c04f73eSAndrey V. Elsukov 44756707beeSMark Johnston if (g_co.use_set != 0 || cfg->set != 0) 4485c04f73eSAndrey V. Elsukov printf("set %u ", cfg->set); 4495c04f73eSAndrey V. Elsukov 4505c04f73eSAndrey V. Elsukov inet_ntop(AF_INET6, &cfg->clat_prefix, clat_buf, sizeof(clat_buf)); 4515c04f73eSAndrey V. Elsukov inet_ntop(AF_INET6, &cfg->plat_prefix, plat_buf, sizeof(plat_buf)); 4525c04f73eSAndrey V. Elsukov printf("nat64clat %s clat_prefix %s/%u plat_prefix %s/%u", 4535c04f73eSAndrey V. Elsukov cfg->name, clat_buf, cfg->clat_plen, plat_buf, cfg->plat_plen); 4545c04f73eSAndrey V. Elsukov if (cfg->flags & NAT64_LOG) 4555c04f73eSAndrey V. Elsukov printf(" log"); 4565c04f73eSAndrey V. Elsukov if (cfg->flags & NAT64_ALLOW_PRIVATE) 4575c04f73eSAndrey V. Elsukov printf(" allow_private"); 4585c04f73eSAndrey V. Elsukov printf("\n"); 4595c04f73eSAndrey V. Elsukov return (0); 4605c04f73eSAndrey V. Elsukov } 4615c04f73eSAndrey V. Elsukov 4625c04f73eSAndrey V. Elsukov static int 46356707beeSMark Johnston nat64clat_destroy_cb(ipfw_nat64clat_cfg *cfg, const char *name __unused, 46456707beeSMark Johnston uint8_t set) 4655c04f73eSAndrey V. Elsukov { 4665c04f73eSAndrey V. Elsukov 46756707beeSMark Johnston if (g_co.use_set != 0 && cfg->set != set) 4685c04f73eSAndrey V. Elsukov return (ESRCH); 4695c04f73eSAndrey V. Elsukov 4705c04f73eSAndrey V. Elsukov nat64clat_destroy(cfg->name, cfg->set); 4715c04f73eSAndrey V. Elsukov return (0); 4725c04f73eSAndrey V. Elsukov } 4735c04f73eSAndrey V. Elsukov 4745c04f73eSAndrey V. Elsukov 4755c04f73eSAndrey V. Elsukov /* 4765c04f73eSAndrey V. Elsukov * Compare nat64clat instances names. 4775c04f73eSAndrey V. Elsukov * Honor number comparison. 4785c04f73eSAndrey V. Elsukov */ 4795c04f73eSAndrey V. Elsukov static int 4805c04f73eSAndrey V. Elsukov nat64name_cmp(const void *a, const void *b) 4815c04f73eSAndrey V. Elsukov { 48256707beeSMark Johnston const ipfw_nat64clat_cfg *ca, *cb; 4835c04f73eSAndrey V. Elsukov 48456707beeSMark Johnston ca = (const ipfw_nat64clat_cfg *)a; 48556707beeSMark Johnston cb = (const ipfw_nat64clat_cfg *)b; 4865c04f73eSAndrey V. Elsukov 4875c04f73eSAndrey V. Elsukov if (ca->set > cb->set) 4885c04f73eSAndrey V. Elsukov return (1); 4895c04f73eSAndrey V. Elsukov else if (ca->set < cb->set) 4905c04f73eSAndrey V. Elsukov return (-1); 4915c04f73eSAndrey V. Elsukov return (stringnum_cmp(ca->name, cb->name)); 4925c04f73eSAndrey V. Elsukov } 4935c04f73eSAndrey V. Elsukov 4945c04f73eSAndrey V. Elsukov /* 4955c04f73eSAndrey V. Elsukov * Retrieves nat64clat instance list from kernel, 4965c04f73eSAndrey V. Elsukov * optionally sorts it and calls requested function for each instance. 4975c04f73eSAndrey V. Elsukov * 4985c04f73eSAndrey V. Elsukov * Request: [ ipfw_obj_lheader ] 4995c04f73eSAndrey V. Elsukov * Reply: [ ipfw_obj_lheader ipfw_nat64clat_cfg x N ] 5005c04f73eSAndrey V. Elsukov */ 5015c04f73eSAndrey V. Elsukov static int 5025c04f73eSAndrey V. Elsukov nat64clat_foreach(nat64clat_cb_t *f, const char *name, uint8_t set, int sort) 5035c04f73eSAndrey V. Elsukov { 5045c04f73eSAndrey V. Elsukov ipfw_obj_lheader *olh; 5055c04f73eSAndrey V. Elsukov ipfw_nat64clat_cfg *cfg; 5065c04f73eSAndrey V. Elsukov size_t sz; 50756707beeSMark Johnston uint32_t i; 50856707beeSMark Johnston int error; 5095c04f73eSAndrey V. Elsukov 5105c04f73eSAndrey V. Elsukov /* Start with reasonable default */ 5115c04f73eSAndrey V. Elsukov sz = sizeof(*olh) + 16 * sizeof(*cfg); 5125c04f73eSAndrey V. Elsukov for (;;) { 5135c04f73eSAndrey V. Elsukov if ((olh = calloc(1, sz)) == NULL) 5145c04f73eSAndrey V. Elsukov return (ENOMEM); 5155c04f73eSAndrey V. Elsukov 5165c04f73eSAndrey V. Elsukov olh->size = sz; 5175c04f73eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64CLAT_LIST, &olh->opheader, &sz) != 0) { 5185c04f73eSAndrey V. Elsukov sz = olh->size; 5195c04f73eSAndrey V. Elsukov free(olh); 5205c04f73eSAndrey V. Elsukov if (errno != ENOMEM) 5215c04f73eSAndrey V. Elsukov return (errno); 5225c04f73eSAndrey V. Elsukov continue; 5235c04f73eSAndrey V. Elsukov } 5245c04f73eSAndrey V. Elsukov 5255c04f73eSAndrey V. Elsukov if (sort != 0) 5265c04f73eSAndrey V. Elsukov qsort(olh + 1, olh->count, olh->objsize, 5275c04f73eSAndrey V. Elsukov nat64name_cmp); 5285c04f73eSAndrey V. Elsukov 5295c04f73eSAndrey V. Elsukov cfg = (ipfw_nat64clat_cfg *)(olh + 1); 5305c04f73eSAndrey V. Elsukov for (i = 0; i < olh->count; i++) { 5315c04f73eSAndrey V. Elsukov error = f(cfg, name, set); /* Ignore errors for now */ 5325c04f73eSAndrey V. Elsukov cfg = (ipfw_nat64clat_cfg *)((caddr_t)cfg + 5335c04f73eSAndrey V. Elsukov olh->objsize); 5345c04f73eSAndrey V. Elsukov } 5355c04f73eSAndrey V. Elsukov free(olh); 5365c04f73eSAndrey V. Elsukov break; 5375c04f73eSAndrey V. Elsukov } 5385c04f73eSAndrey V. Elsukov return (0); 5395c04f73eSAndrey V. Elsukov } 5405c04f73eSAndrey V. Elsukov 541