1d8caf56eSAndrey V. Elsukov /*- 2d8caf56eSAndrey V. Elsukov * Copyright (c) 2015-2016 Yandex LLC 3d8caf56eSAndrey V. Elsukov * Copyright (c) 2015-2016 Alexander V. Chernikov <melifaro@FreeBSD.org> 4d8caf56eSAndrey V. Elsukov * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org> 5d8caf56eSAndrey V. Elsukov * All rights reserved. 6d8caf56eSAndrey V. Elsukov * 7d8caf56eSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without 8d8caf56eSAndrey V. Elsukov * modification, are permitted provided that the following conditions 9d8caf56eSAndrey V. Elsukov * are met: 10d8caf56eSAndrey V. Elsukov * 11d8caf56eSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright 12d8caf56eSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer. 13d8caf56eSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright 14d8caf56eSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the 15d8caf56eSAndrey V. Elsukov * documentation and/or other materials provided with the distribution. 16d8caf56eSAndrey V. Elsukov * 17d8caf56eSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18d8caf56eSAndrey V. Elsukov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19d8caf56eSAndrey V. Elsukov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20d8caf56eSAndrey V. Elsukov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21d8caf56eSAndrey V. Elsukov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22d8caf56eSAndrey V. Elsukov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23d8caf56eSAndrey V. Elsukov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24d8caf56eSAndrey V. Elsukov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25d8caf56eSAndrey V. Elsukov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26d8caf56eSAndrey V. Elsukov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27d8caf56eSAndrey V. Elsukov */ 28d8caf56eSAndrey V. Elsukov 29d8caf56eSAndrey V. Elsukov #include <sys/cdefs.h> 30d8caf56eSAndrey V. Elsukov __FBSDID("$FreeBSD$"); 31d8caf56eSAndrey V. Elsukov 32d8caf56eSAndrey V. Elsukov #include <sys/types.h> 33d8caf56eSAndrey V. Elsukov #include <sys/socket.h> 34d8caf56eSAndrey V. Elsukov 35d8caf56eSAndrey V. Elsukov #include "ipfw2.h" 36d8caf56eSAndrey V. Elsukov 37d8caf56eSAndrey V. Elsukov #include <ctype.h> 38d8caf56eSAndrey V. Elsukov #include <err.h> 39d8caf56eSAndrey V. Elsukov #include <errno.h> 40c5e85276SAndrey V. Elsukov #include <inttypes.h> 41d8caf56eSAndrey V. Elsukov #include <netdb.h> 42d8caf56eSAndrey V. Elsukov #include <stdio.h> 43d8caf56eSAndrey V. Elsukov #include <stdlib.h> 44d8caf56eSAndrey V. Elsukov #include <string.h> 45d8caf56eSAndrey V. Elsukov #include <sysexits.h> 46d8caf56eSAndrey V. Elsukov 47d8caf56eSAndrey V. Elsukov #include <net/if.h> 48d8caf56eSAndrey V. Elsukov #include <netinet/in.h> 49d8caf56eSAndrey V. Elsukov #include <netinet/ip_fw.h> 50d8caf56eSAndrey V. Elsukov #include <netinet6/ip_fw_nat64.h> 51d8caf56eSAndrey V. Elsukov #include <arpa/inet.h> 52d8caf56eSAndrey V. Elsukov 53d8caf56eSAndrey V. Elsukov static void nat64lsn_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, 54d8caf56eSAndrey V. Elsukov uint8_t set); 55d8caf56eSAndrey V. Elsukov typedef int (nat64lsn_cb_t)(ipfw_nat64lsn_cfg *cfg, const char *name, 56d8caf56eSAndrey V. Elsukov uint8_t set); 57d8caf56eSAndrey V. Elsukov static int nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set, 58d8caf56eSAndrey V. Elsukov int sort); 59d8caf56eSAndrey V. Elsukov 60d8caf56eSAndrey V. Elsukov static void nat64lsn_create(const char *name, uint8_t set, int ac, char **av); 61d8caf56eSAndrey V. Elsukov static void nat64lsn_config(const char *name, uint8_t set, int ac, char **av); 62d8caf56eSAndrey V. Elsukov static void nat64lsn_destroy(const char *name, uint8_t set); 63d8caf56eSAndrey V. Elsukov static void nat64lsn_stats(const char *name, uint8_t set); 64d8caf56eSAndrey V. Elsukov static void nat64lsn_reset_stats(const char *name, uint8_t set); 65d8caf56eSAndrey V. Elsukov static int nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name, 66d8caf56eSAndrey V. Elsukov uint8_t set); 67d8caf56eSAndrey V. Elsukov static int nat64lsn_destroy_cb(ipfw_nat64lsn_cfg *cfg, const char *name, 68d8caf56eSAndrey V. Elsukov uint8_t set); 69d8caf56eSAndrey V. Elsukov static int nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name, 70d8caf56eSAndrey V. Elsukov uint8_t set); 71d8caf56eSAndrey V. Elsukov 72d8caf56eSAndrey V. Elsukov static struct _s_x nat64cmds[] = { 73d8caf56eSAndrey V. Elsukov { "create", TOK_CREATE }, 74d8caf56eSAndrey V. Elsukov { "config", TOK_CONFIG }, 75d8caf56eSAndrey V. Elsukov { "destroy", TOK_DESTROY }, 76d8caf56eSAndrey V. Elsukov { "list", TOK_LIST }, 77d8caf56eSAndrey V. Elsukov { "show", TOK_LIST }, 78d8caf56eSAndrey V. Elsukov { "stats", TOK_STATS }, 79d8caf56eSAndrey V. Elsukov { NULL, 0 } 80d8caf56eSAndrey V. Elsukov }; 81d8caf56eSAndrey V. Elsukov 82d8caf56eSAndrey V. Elsukov static uint64_t 83d8caf56eSAndrey V. Elsukov nat64lsn_print_states(void *buf) 84d8caf56eSAndrey V. Elsukov { 85d8caf56eSAndrey V. Elsukov char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], f[INET_ADDRSTRLEN]; 86d8caf56eSAndrey V. Elsukov char sflags[4], *sf, *proto; 87d8caf56eSAndrey V. Elsukov ipfw_obj_header *oh; 88d8caf56eSAndrey V. Elsukov ipfw_obj_data *od; 89d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_stg *stg; 90d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_state *ste; 91d8caf56eSAndrey V. Elsukov uint64_t next_idx; 92d8caf56eSAndrey V. Elsukov int i, sz; 93d8caf56eSAndrey V. Elsukov 94d8caf56eSAndrey V. Elsukov oh = (ipfw_obj_header *)buf; 95d8caf56eSAndrey V. Elsukov od = (ipfw_obj_data *)(oh + 1); 96d8caf56eSAndrey V. Elsukov stg = (ipfw_nat64lsn_stg *)(od + 1); 97d8caf56eSAndrey V. Elsukov sz = od->head.length - sizeof(*od); 98d8caf56eSAndrey V. Elsukov next_idx = 0; 99d8caf56eSAndrey V. Elsukov while (sz > 0 && next_idx != 0xFF) { 100d8caf56eSAndrey V. Elsukov next_idx = stg->next_idx; 101d8caf56eSAndrey V. Elsukov sz -= sizeof(*stg); 102d8caf56eSAndrey V. Elsukov if (stg->count == 0) { 103d8caf56eSAndrey V. Elsukov stg++; 104d8caf56eSAndrey V. Elsukov continue; 105d8caf56eSAndrey V. Elsukov } 106d8caf56eSAndrey V. Elsukov switch (stg->proto) { 107d8caf56eSAndrey V. Elsukov case IPPROTO_TCP: 108d8caf56eSAndrey V. Elsukov proto = "TCP"; 109d8caf56eSAndrey V. Elsukov break; 110d8caf56eSAndrey V. Elsukov case IPPROTO_UDP: 111d8caf56eSAndrey V. Elsukov proto = "UDP"; 112d8caf56eSAndrey V. Elsukov break; 113d8caf56eSAndrey V. Elsukov case IPPROTO_ICMPV6: 114d8caf56eSAndrey V. Elsukov proto = "ICMPv6"; 115d8caf56eSAndrey V. Elsukov break; 116d8caf56eSAndrey V. Elsukov } 117d8caf56eSAndrey V. Elsukov inet_ntop(AF_INET6, &stg->host6, s, sizeof(s)); 118d8caf56eSAndrey V. Elsukov inet_ntop(AF_INET, &stg->alias4, a, sizeof(a)); 119d8caf56eSAndrey V. Elsukov ste = (ipfw_nat64lsn_state *)(stg + 1); 120d8caf56eSAndrey V. Elsukov for (i = 0; i < stg->count && sz > 0; i++) { 121d8caf56eSAndrey V. Elsukov sf = sflags; 122d8caf56eSAndrey V. Elsukov inet_ntop(AF_INET, &ste->daddr, f, sizeof(f)); 123d8caf56eSAndrey V. Elsukov if (stg->proto == IPPROTO_TCP) { 124d8caf56eSAndrey V. Elsukov if (ste->flags & 0x02) 125d8caf56eSAndrey V. Elsukov *sf++ = 'S'; 126d8caf56eSAndrey V. Elsukov if (ste->flags & 0x04) 127d8caf56eSAndrey V. Elsukov *sf++ = 'E'; 128d8caf56eSAndrey V. Elsukov if (ste->flags & 0x01) 129d8caf56eSAndrey V. Elsukov *sf++ = 'F'; 130d8caf56eSAndrey V. Elsukov } 131d8caf56eSAndrey V. Elsukov *sf = '\0'; 132d8caf56eSAndrey V. Elsukov switch (stg->proto) { 133d8caf56eSAndrey V. Elsukov case IPPROTO_TCP: 134d8caf56eSAndrey V. Elsukov case IPPROTO_UDP: 135d8caf56eSAndrey V. Elsukov printf("%s:%d\t%s:%d\t%s\t%s\t%d\t%s:%d\n", 136d8caf56eSAndrey V. Elsukov s, ste->sport, a, ste->aport, proto, 137d8caf56eSAndrey V. Elsukov sflags, ste->idle, f, ste->dport); 138d8caf56eSAndrey V. Elsukov break; 139d8caf56eSAndrey V. Elsukov case IPPROTO_ICMPV6: 140d8caf56eSAndrey V. Elsukov printf("%s\t%s\t%s\t\t%d\t%s\n", 141d8caf56eSAndrey V. Elsukov s, a, proto, ste->idle, f); 142d8caf56eSAndrey V. Elsukov break; 143d8caf56eSAndrey V. Elsukov default: 144d8caf56eSAndrey V. Elsukov printf("%s\t%s\t%d\t\t%d\t%s\n", 145d8caf56eSAndrey V. Elsukov s, a, stg->proto, ste->idle, f); 146d8caf56eSAndrey V. Elsukov } 147d8caf56eSAndrey V. Elsukov ste++; 148d8caf56eSAndrey V. Elsukov sz -= sizeof(*ste); 149d8caf56eSAndrey V. Elsukov } 150d8caf56eSAndrey V. Elsukov stg = (ipfw_nat64lsn_stg *)ste; 151d8caf56eSAndrey V. Elsukov } 152d8caf56eSAndrey V. Elsukov return (next_idx); 153d8caf56eSAndrey V. Elsukov } 154d8caf56eSAndrey V. Elsukov 155d8caf56eSAndrey V. Elsukov static int 156d8caf56eSAndrey V. Elsukov nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set) 157d8caf56eSAndrey V. Elsukov { 158d8caf56eSAndrey V. Elsukov ipfw_obj_header *oh; 159d8caf56eSAndrey V. Elsukov ipfw_obj_data *od; 160d8caf56eSAndrey V. Elsukov void *buf; 161d8caf56eSAndrey V. Elsukov uint64_t next_idx; 162d8caf56eSAndrey V. Elsukov size_t sz; 163d8caf56eSAndrey V. Elsukov 164d8caf56eSAndrey V. Elsukov if (name != NULL && strcmp(cfg->name, name) != 0) 165d8caf56eSAndrey V. Elsukov return (ESRCH); 166d8caf56eSAndrey V. Elsukov 167d8caf56eSAndrey V. Elsukov if (set != 0 && cfg->set != set) 168d8caf56eSAndrey V. Elsukov return (ESRCH); 169d8caf56eSAndrey V. Elsukov 170d8caf56eSAndrey V. Elsukov next_idx = 0; 171d8caf56eSAndrey V. Elsukov sz = 4096; 172d8caf56eSAndrey V. Elsukov if ((buf = calloc(1, sz)) == NULL) 173d8caf56eSAndrey V. Elsukov err(EX_OSERR, NULL); 174d8caf56eSAndrey V. Elsukov do { 175d8caf56eSAndrey V. Elsukov oh = (ipfw_obj_header *)buf; 176d8caf56eSAndrey V. Elsukov od = (ipfw_obj_data *)(oh + 1); 177d8caf56eSAndrey V. Elsukov nat64lsn_fill_ntlv(&oh->ntlv, cfg->name, set); 178d8caf56eSAndrey V. Elsukov od->head.type = IPFW_TLV_OBJDATA; 179d8caf56eSAndrey V. Elsukov od->head.length = sizeof(*od) + sizeof(next_idx); 180d8caf56eSAndrey V. Elsukov *((uint64_t *)(od + 1)) = next_idx; 181d8caf56eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64LSN_LIST_STATES, &oh->opheader, &sz)) 182d8caf56eSAndrey V. Elsukov err(EX_OSERR, "Error reading nat64lsn states"); 183d8caf56eSAndrey V. Elsukov next_idx = nat64lsn_print_states(buf); 184d8caf56eSAndrey V. Elsukov sz = 4096; 185d8caf56eSAndrey V. Elsukov memset(buf, 0, sz); 186d8caf56eSAndrey V. Elsukov } while (next_idx != 0xFF); 187d8caf56eSAndrey V. Elsukov 188d8caf56eSAndrey V. Elsukov free(buf); 189d8caf56eSAndrey V. Elsukov return (0); 190d8caf56eSAndrey V. Elsukov } 191d8caf56eSAndrey V. Elsukov 192d8caf56eSAndrey V. Elsukov static struct _s_x nat64statscmds[] = { 193d8caf56eSAndrey V. Elsukov { "reset", TOK_RESET }, 194d8caf56eSAndrey V. Elsukov { NULL, 0 } 195d8caf56eSAndrey V. Elsukov }; 196d8caf56eSAndrey V. Elsukov 197d8caf56eSAndrey V. Elsukov static void 198d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_stats_handler(const char *name, uint8_t set, int ac, char *av[]) 199d8caf56eSAndrey V. Elsukov { 200d8caf56eSAndrey V. Elsukov int tcmd; 201d8caf56eSAndrey V. Elsukov 202d8caf56eSAndrey V. Elsukov if (ac == 0) { 203d8caf56eSAndrey V. Elsukov nat64lsn_stats(name, set); 204d8caf56eSAndrey V. Elsukov return; 205d8caf56eSAndrey V. Elsukov } 206d8caf56eSAndrey V. Elsukov NEED1("nat64lsn stats needs command"); 207d8caf56eSAndrey V. Elsukov tcmd = get_token(nat64statscmds, *av, "nat64lsn stats command"); 208d8caf56eSAndrey V. Elsukov switch (tcmd) { 209d8caf56eSAndrey V. Elsukov case TOK_RESET: 210d8caf56eSAndrey V. Elsukov nat64lsn_reset_stats(name, set); 211d8caf56eSAndrey V. Elsukov } 212d8caf56eSAndrey V. Elsukov } 213d8caf56eSAndrey V. Elsukov 214d8caf56eSAndrey V. Elsukov static struct _s_x nat64listcmds[] = { 215d8caf56eSAndrey V. Elsukov { "states", TOK_STATES }, 216d8caf56eSAndrey V. Elsukov { "config", TOK_CONFIG }, 217d8caf56eSAndrey V. Elsukov { NULL, 0 } 218d8caf56eSAndrey V. Elsukov }; 219d8caf56eSAndrey V. Elsukov 220d8caf56eSAndrey V. Elsukov static void 221d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_list_handler(const char *name, uint8_t set, int ac, char *av[]) 222d8caf56eSAndrey V. Elsukov { 223d8caf56eSAndrey V. Elsukov int tcmd; 224d8caf56eSAndrey V. Elsukov 225d8caf56eSAndrey V. Elsukov if (ac == 0) { 226d8caf56eSAndrey V. Elsukov nat64lsn_foreach(nat64lsn_show_cb, name, set, 1); 227d8caf56eSAndrey V. Elsukov return; 228d8caf56eSAndrey V. Elsukov } 229d8caf56eSAndrey V. Elsukov NEED1("nat64lsn list needs command"); 230d8caf56eSAndrey V. Elsukov tcmd = get_token(nat64listcmds, *av, "nat64lsn list command"); 231d8caf56eSAndrey V. Elsukov switch (tcmd) { 232d8caf56eSAndrey V. Elsukov case TOK_STATES: 233d8caf56eSAndrey V. Elsukov nat64lsn_foreach(nat64lsn_states_cb, name, set, 1); 234d8caf56eSAndrey V. Elsukov break; 235d8caf56eSAndrey V. Elsukov case TOK_CONFIG: 236d8caf56eSAndrey V. Elsukov nat64lsn_foreach(nat64lsn_show_cb, name, set, 1); 237d8caf56eSAndrey V. Elsukov } 238d8caf56eSAndrey V. Elsukov } 239d8caf56eSAndrey V. Elsukov 240d8caf56eSAndrey V. Elsukov /* 241d8caf56eSAndrey V. Elsukov * This one handles all nat64lsn-related commands 242d8caf56eSAndrey V. Elsukov * ipfw [set N] nat64lsn NAME {create | config} ... 243d8caf56eSAndrey V. Elsukov * ipfw [set N] nat64lsn NAME stats 244d8caf56eSAndrey V. Elsukov * ipfw [set N] nat64lsn {NAME | all} destroy 245d8caf56eSAndrey V. Elsukov * ipfw [set N] nat64lsn {NAME | all} {list | show} [config | states] 246d8caf56eSAndrey V. Elsukov */ 247d8caf56eSAndrey V. Elsukov #define nat64lsn_check_name table_check_name 248d8caf56eSAndrey V. Elsukov void 249d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_handler(int ac, char *av[]) 250d8caf56eSAndrey V. Elsukov { 251d8caf56eSAndrey V. Elsukov const char *name; 252d8caf56eSAndrey V. Elsukov int tcmd; 253d8caf56eSAndrey V. Elsukov uint8_t set; 254d8caf56eSAndrey V. Elsukov 255d8caf56eSAndrey V. Elsukov if (co.use_set != 0) 256d8caf56eSAndrey V. Elsukov set = co.use_set - 1; 257d8caf56eSAndrey V. Elsukov else 258d8caf56eSAndrey V. Elsukov set = 0; 259d8caf56eSAndrey V. Elsukov ac--; av++; 260d8caf56eSAndrey V. Elsukov 261d8caf56eSAndrey V. Elsukov NEED1("nat64lsn needs instance name"); 262d8caf56eSAndrey V. Elsukov name = *av; 263d8caf56eSAndrey V. Elsukov if (nat64lsn_check_name(name) != 0) { 264d8caf56eSAndrey V. Elsukov if (strcmp(name, "all") == 0) 265d8caf56eSAndrey V. Elsukov name = NULL; 266d8caf56eSAndrey V. Elsukov else 267d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "nat64lsn instance name %s is invalid", 268d8caf56eSAndrey V. Elsukov name); 269d8caf56eSAndrey V. Elsukov } 270d8caf56eSAndrey V. Elsukov ac--; av++; 271d8caf56eSAndrey V. Elsukov NEED1("nat64lsn needs command"); 272d8caf56eSAndrey V. Elsukov 273d8caf56eSAndrey V. Elsukov tcmd = get_token(nat64cmds, *av, "nat64lsn command"); 274d8caf56eSAndrey V. Elsukov if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST) 275d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "nat64lsn instance name required"); 276d8caf56eSAndrey V. Elsukov switch (tcmd) { 277d8caf56eSAndrey V. Elsukov case TOK_CREATE: 278d8caf56eSAndrey V. Elsukov ac--; av++; 279d8caf56eSAndrey V. Elsukov nat64lsn_create(name, set, ac, av); 280d8caf56eSAndrey V. Elsukov break; 281d8caf56eSAndrey V. Elsukov case TOK_CONFIG: 282d8caf56eSAndrey V. Elsukov ac--; av++; 283d8caf56eSAndrey V. Elsukov nat64lsn_config(name, set, ac, av); 284d8caf56eSAndrey V. Elsukov break; 285d8caf56eSAndrey V. Elsukov case TOK_LIST: 286d8caf56eSAndrey V. Elsukov ac--; av++; 287d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_list_handler(name, set, ac, av); 288d8caf56eSAndrey V. Elsukov break; 289d8caf56eSAndrey V. Elsukov case TOK_DESTROY: 290d8caf56eSAndrey V. Elsukov if (name == NULL) 291d8caf56eSAndrey V. Elsukov nat64lsn_foreach(nat64lsn_destroy_cb, NULL, set, 0); 292d8caf56eSAndrey V. Elsukov else 293d8caf56eSAndrey V. Elsukov nat64lsn_destroy(name, set); 294d8caf56eSAndrey V. Elsukov break; 295d8caf56eSAndrey V. Elsukov case TOK_STATS: 296d8caf56eSAndrey V. Elsukov ac--; av++; 297d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_stats_handler(name, set, ac, av); 298d8caf56eSAndrey V. Elsukov } 299d8caf56eSAndrey V. Elsukov } 300d8caf56eSAndrey V. Elsukov 301d8caf56eSAndrey V. Elsukov static void 302d8caf56eSAndrey V. Elsukov nat64lsn_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set) 303d8caf56eSAndrey V. Elsukov { 304d8caf56eSAndrey V. Elsukov 305d8caf56eSAndrey V. Elsukov ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */ 306d8caf56eSAndrey V. Elsukov ntlv->head.length = sizeof(ipfw_obj_ntlv); 307d8caf56eSAndrey V. Elsukov ntlv->idx = 1; 308d8caf56eSAndrey V. Elsukov ntlv->set = set; 309d8caf56eSAndrey V. Elsukov strlcpy(ntlv->name, name, sizeof(ntlv->name)); 310d8caf56eSAndrey V. Elsukov } 311d8caf56eSAndrey V. Elsukov 312d8caf56eSAndrey V. Elsukov static void 313d8caf56eSAndrey V. Elsukov nat64lsn_apply_mask(int af, void *prefix, uint16_t plen) 314d8caf56eSAndrey V. Elsukov { 315d8caf56eSAndrey V. Elsukov struct in6_addr mask6, *p6; 316d8caf56eSAndrey V. Elsukov struct in_addr mask4, *p4; 317d8caf56eSAndrey V. Elsukov 318d8caf56eSAndrey V. Elsukov if (af == AF_INET) { 319d8caf56eSAndrey V. Elsukov p4 = (struct in_addr *)prefix; 320d8caf56eSAndrey V. Elsukov mask4.s_addr = htonl(~((1 << (32 - plen)) - 1)); 321d8caf56eSAndrey V. Elsukov p4->s_addr &= mask4.s_addr; 322d8caf56eSAndrey V. Elsukov } else if (af == AF_INET6) { 323d8caf56eSAndrey V. Elsukov p6 = (struct in6_addr *)prefix; 324d8caf56eSAndrey V. Elsukov n2mask(&mask6, plen); 325d8caf56eSAndrey V. Elsukov APPLY_MASK(p6, &mask6); 326d8caf56eSAndrey V. Elsukov } 327d8caf56eSAndrey V. Elsukov } 328d8caf56eSAndrey V. Elsukov 329d8caf56eSAndrey V. Elsukov static void 330d8caf56eSAndrey V. Elsukov nat64lsn_parse_prefix(const char *arg, int af, void *prefix, uint16_t *plen) 331d8caf56eSAndrey V. Elsukov { 332d8caf56eSAndrey V. Elsukov char *p, *l; 333d8caf56eSAndrey V. Elsukov 334d8caf56eSAndrey V. Elsukov p = strdup(arg); 335d8caf56eSAndrey V. Elsukov if (p == NULL) 336d8caf56eSAndrey V. Elsukov err(EX_OSERR, NULL); 337d8caf56eSAndrey V. Elsukov if ((l = strchr(p, '/')) != NULL) 338d8caf56eSAndrey V. Elsukov *l++ = '\0'; 339d8caf56eSAndrey V. Elsukov if (l == NULL) 340d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "Prefix length required"); 341d8caf56eSAndrey V. Elsukov if (inet_pton(af, p, prefix) != 1) 342d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "Bad prefix: %s", p); 343d8caf56eSAndrey V. Elsukov *plen = (uint16_t)strtol(l, &l, 10); 344d8caf56eSAndrey V. Elsukov if (*l != '\0' || *plen == 0 || (af == AF_INET && *plen > 32) || 345d8caf56eSAndrey V. Elsukov (af == AF_INET6 && *plen > 96)) 346d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "Bad prefix length: %s", arg); 347d8caf56eSAndrey V. Elsukov nat64lsn_apply_mask(af, prefix, *plen); 348d8caf56eSAndrey V. Elsukov free(p); 349d8caf56eSAndrey V. Elsukov } 350d8caf56eSAndrey V. Elsukov 351d8caf56eSAndrey V. Elsukov static uint32_t 352d8caf56eSAndrey V. Elsukov nat64lsn_parse_int(const char *arg, const char *desc) 353d8caf56eSAndrey V. Elsukov { 354d8caf56eSAndrey V. Elsukov char *p; 355d8caf56eSAndrey V. Elsukov uint32_t val; 356d8caf56eSAndrey V. Elsukov 357d8caf56eSAndrey V. Elsukov val = (uint32_t)strtol(arg, &p, 10); 358d8caf56eSAndrey V. Elsukov if (*p != '\0') 359d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "Invalid %s value: %s\n", desc, arg); 360d8caf56eSAndrey V. Elsukov return (val); 361d8caf56eSAndrey V. Elsukov } 362d8caf56eSAndrey V. Elsukov 363d8caf56eSAndrey V. Elsukov static struct _s_x nat64newcmds[] = { 364d8caf56eSAndrey V. Elsukov { "prefix6", TOK_PREFIX6 }, 365d8caf56eSAndrey V. Elsukov { "agg_len", TOK_AGG_LEN }, /* not yet */ 366d8caf56eSAndrey V. Elsukov { "agg_count", TOK_AGG_COUNT }, /* not yet */ 367d8caf56eSAndrey V. Elsukov { "port_range", TOK_PORT_RANGE }, /* not yet */ 368d8caf56eSAndrey V. Elsukov { "jmaxlen", TOK_JMAXLEN }, 369d8caf56eSAndrey V. Elsukov { "prefix4", TOK_PREFIX4 }, 370d8caf56eSAndrey V. Elsukov { "max_ports", TOK_MAX_PORTS }, 371d8caf56eSAndrey V. Elsukov { "host_del_age", TOK_HOST_DEL_AGE }, 372d8caf56eSAndrey V. Elsukov { "pg_del_age", TOK_PG_DEL_AGE }, 373d8caf56eSAndrey V. Elsukov { "tcp_syn_age", TOK_TCP_SYN_AGE }, 374d8caf56eSAndrey V. Elsukov { "tcp_close_age",TOK_TCP_CLOSE_AGE }, 375d8caf56eSAndrey V. Elsukov { "tcp_est_age", TOK_TCP_EST_AGE }, 376d8caf56eSAndrey V. Elsukov { "udp_age", TOK_UDP_AGE }, 377d8caf56eSAndrey V. Elsukov { "icmp_age", TOK_ICMP_AGE }, 378d8caf56eSAndrey V. Elsukov { "log", TOK_LOG }, 379d8caf56eSAndrey V. Elsukov { "-log", TOK_LOGOFF }, 380*b11efc1eSAndrey V. Elsukov { "allow_private", TOK_PRIVATE }, 381*b11efc1eSAndrey V. Elsukov { "-allow_private", TOK_PRIVATEOFF }, 382d8caf56eSAndrey V. Elsukov { NULL, 0 } 383d8caf56eSAndrey V. Elsukov }; 384d8caf56eSAndrey V. Elsukov 385d8caf56eSAndrey V. Elsukov /* 386d8caf56eSAndrey V. Elsukov * Creates new nat64lsn instance 387d8caf56eSAndrey V. Elsukov * ipfw nat64lsn <NAME> create 388d8caf56eSAndrey V. Elsukov * [ max_ports <N> ] 389d8caf56eSAndrey V. Elsukov * Request: [ ipfw_obj_lheader ipfw_nat64lsn_cfg ] 390d8caf56eSAndrey V. Elsukov */ 391d8caf56eSAndrey V. Elsukov #define NAT64LSN_HAS_PREFIX4 0x01 392d8caf56eSAndrey V. Elsukov #define NAT64LSN_HAS_PREFIX6 0x02 393d8caf56eSAndrey V. Elsukov static void 394d8caf56eSAndrey V. Elsukov nat64lsn_create(const char *name, uint8_t set, int ac, char **av) 395d8caf56eSAndrey V. Elsukov { 396d8caf56eSAndrey V. Elsukov char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64lsn_cfg)]; 397d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_cfg *cfg; 398d8caf56eSAndrey V. Elsukov ipfw_obj_lheader *olh; 399d8caf56eSAndrey V. Elsukov int tcmd, flags; 400d8caf56eSAndrey V. Elsukov char *opt; 401d8caf56eSAndrey V. Elsukov 402d8caf56eSAndrey V. Elsukov memset(&buf, 0, sizeof(buf)); 403d8caf56eSAndrey V. Elsukov olh = (ipfw_obj_lheader *)buf; 404d8caf56eSAndrey V. Elsukov cfg = (ipfw_nat64lsn_cfg *)(olh + 1); 405d8caf56eSAndrey V. Elsukov 406d8caf56eSAndrey V. Elsukov /* Some reasonable defaults */ 407d8caf56eSAndrey V. Elsukov inet_pton(AF_INET6, "64:ff9b::", &cfg->prefix6); 408d8caf56eSAndrey V. Elsukov cfg->plen6 = 96; 409d8caf56eSAndrey V. Elsukov cfg->set = set; 410d8caf56eSAndrey V. Elsukov cfg->max_ports = NAT64LSN_MAX_PORTS; 411d8caf56eSAndrey V. Elsukov cfg->jmaxlen = NAT64LSN_JMAXLEN; 412d8caf56eSAndrey V. Elsukov cfg->nh_delete_delay = NAT64LSN_HOST_AGE; 413d8caf56eSAndrey V. Elsukov cfg->pg_delete_delay = NAT64LSN_PG_AGE; 414d8caf56eSAndrey V. Elsukov cfg->st_syn_ttl = NAT64LSN_TCP_SYN_AGE; 415d8caf56eSAndrey V. Elsukov cfg->st_estab_ttl = NAT64LSN_TCP_EST_AGE; 416d8caf56eSAndrey V. Elsukov cfg->st_close_ttl = NAT64LSN_TCP_FIN_AGE; 417d8caf56eSAndrey V. Elsukov cfg->st_udp_ttl = NAT64LSN_UDP_AGE; 418d8caf56eSAndrey V. Elsukov cfg->st_icmp_ttl = NAT64LSN_ICMP_AGE; 419d8caf56eSAndrey V. Elsukov flags = NAT64LSN_HAS_PREFIX6; 420d8caf56eSAndrey V. Elsukov while (ac > 0) { 421d8caf56eSAndrey V. Elsukov tcmd = get_token(nat64newcmds, *av, "option"); 422d8caf56eSAndrey V. Elsukov opt = *av; 423d8caf56eSAndrey V. Elsukov ac--; av++; 424d8caf56eSAndrey V. Elsukov 425d8caf56eSAndrey V. Elsukov switch (tcmd) { 426d8caf56eSAndrey V. Elsukov case TOK_PREFIX4: 427d8caf56eSAndrey V. Elsukov NEED1("IPv4 prefix required"); 428d8caf56eSAndrey V. Elsukov nat64lsn_parse_prefix(*av, AF_INET, &cfg->prefix4, 429d8caf56eSAndrey V. Elsukov &cfg->plen4); 430d8caf56eSAndrey V. Elsukov flags |= NAT64LSN_HAS_PREFIX4; 431d8caf56eSAndrey V. Elsukov ac--; av++; 432d8caf56eSAndrey V. Elsukov break; 433d8caf56eSAndrey V. Elsukov case TOK_PREFIX6: 434d8caf56eSAndrey V. Elsukov NEED1("IPv6 prefix required"); 435d8caf56eSAndrey V. Elsukov nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6, 436d8caf56eSAndrey V. Elsukov &cfg->plen6); 437782360deSAndrey V. Elsukov if (ipfw_check_nat64prefix(&cfg->prefix6, 438782360deSAndrey V. Elsukov cfg->plen6) != 0) 439782360deSAndrey V. Elsukov errx(EX_USAGE, "Bad prefix6 %s", *av); 440782360deSAndrey V. Elsukov 441d8caf56eSAndrey V. Elsukov ac--; av++; 442d8caf56eSAndrey V. Elsukov break; 443782360deSAndrey V. Elsukov #if 0 444d8caf56eSAndrey V. Elsukov case TOK_AGG_LEN: 445d8caf56eSAndrey V. Elsukov NEED1("Aggregation prefix len required"); 446d8caf56eSAndrey V. Elsukov cfg->agg_prefix_len = nat64lsn_parse_int(*av, opt); 447d8caf56eSAndrey V. Elsukov ac--; av++; 448d8caf56eSAndrey V. Elsukov break; 449d8caf56eSAndrey V. Elsukov case TOK_AGG_COUNT: 450d8caf56eSAndrey V. Elsukov NEED1("Max per-prefix count required"); 451d8caf56eSAndrey V. Elsukov cfg->agg_prefix_max = nat64lsn_parse_int(*av, opt); 452d8caf56eSAndrey V. Elsukov ac--; av++; 453d8caf56eSAndrey V. Elsukov break; 454d8caf56eSAndrey V. Elsukov case TOK_PORT_RANGE: 455d8caf56eSAndrey V. Elsukov NEED1("port range x[:y] required"); 456d8caf56eSAndrey V. Elsukov if ((p = strchr(*av, ':')) == NULL) 457d8caf56eSAndrey V. Elsukov cfg->min_port = (uint16_t)nat64lsn_parse_int( 458d8caf56eSAndrey V. Elsukov *av, opt); 459d8caf56eSAndrey V. Elsukov else { 460d8caf56eSAndrey V. Elsukov *p++ = '\0'; 461d8caf56eSAndrey V. Elsukov cfg->min_port = (uint16_t)nat64lsn_parse_int( 462d8caf56eSAndrey V. Elsukov *av, opt); 463d8caf56eSAndrey V. Elsukov cfg->max_port = (uint16_t)nat64lsn_parse_int( 464d8caf56eSAndrey V. Elsukov p, opt); 465d8caf56eSAndrey V. Elsukov } 466d8caf56eSAndrey V. Elsukov ac--; av++; 467d8caf56eSAndrey V. Elsukov break; 468d8caf56eSAndrey V. Elsukov case TOK_JMAXLEN: 469d8caf56eSAndrey V. Elsukov NEED1("job queue length required"); 470d8caf56eSAndrey V. Elsukov cfg->jmaxlen = nat64lsn_parse_int(*av, opt); 471d8caf56eSAndrey V. Elsukov ac--; av++; 472d8caf56eSAndrey V. Elsukov break; 473d8caf56eSAndrey V. Elsukov #endif 474d8caf56eSAndrey V. Elsukov case TOK_MAX_PORTS: 475d8caf56eSAndrey V. Elsukov NEED1("Max per-user ports required"); 476d8caf56eSAndrey V. Elsukov cfg->max_ports = nat64lsn_parse_int(*av, opt); 477d8caf56eSAndrey V. Elsukov ac--; av++; 478d8caf56eSAndrey V. Elsukov break; 479d8caf56eSAndrey V. Elsukov case TOK_HOST_DEL_AGE: 480d8caf56eSAndrey V. Elsukov NEED1("host delete delay required"); 481d8caf56eSAndrey V. Elsukov cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int( 482d8caf56eSAndrey V. Elsukov *av, opt); 483d8caf56eSAndrey V. Elsukov ac--; av++; 484d8caf56eSAndrey V. Elsukov break; 485d8caf56eSAndrey V. Elsukov case TOK_PG_DEL_AGE: 486d8caf56eSAndrey V. Elsukov NEED1("portgroup delete delay required"); 487d8caf56eSAndrey V. Elsukov cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int( 488d8caf56eSAndrey V. Elsukov *av, opt); 489d8caf56eSAndrey V. Elsukov ac--; av++; 490d8caf56eSAndrey V. Elsukov break; 491d8caf56eSAndrey V. Elsukov case TOK_TCP_SYN_AGE: 492d8caf56eSAndrey V. Elsukov NEED1("tcp syn age required"); 493d8caf56eSAndrey V. Elsukov cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int( 494d8caf56eSAndrey V. Elsukov *av, opt); 495d8caf56eSAndrey V. Elsukov ac--; av++; 496d8caf56eSAndrey V. Elsukov break; 497d8caf56eSAndrey V. Elsukov case TOK_TCP_CLOSE_AGE: 498d8caf56eSAndrey V. Elsukov NEED1("tcp close age required"); 499d8caf56eSAndrey V. Elsukov cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int( 500d8caf56eSAndrey V. Elsukov *av, opt); 501d8caf56eSAndrey V. Elsukov ac--; av++; 502d8caf56eSAndrey V. Elsukov break; 503d8caf56eSAndrey V. Elsukov case TOK_TCP_EST_AGE: 504d8caf56eSAndrey V. Elsukov NEED1("tcp est age required"); 505d8caf56eSAndrey V. Elsukov cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int( 506d8caf56eSAndrey V. Elsukov *av, opt); 507d8caf56eSAndrey V. Elsukov ac--; av++; 508d8caf56eSAndrey V. Elsukov break; 509d8caf56eSAndrey V. Elsukov case TOK_UDP_AGE: 510d8caf56eSAndrey V. Elsukov NEED1("udp age required"); 511d8caf56eSAndrey V. Elsukov cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int( 512d8caf56eSAndrey V. Elsukov *av, opt); 513d8caf56eSAndrey V. Elsukov ac--; av++; 514d8caf56eSAndrey V. Elsukov break; 515d8caf56eSAndrey V. Elsukov case TOK_ICMP_AGE: 516d8caf56eSAndrey V. Elsukov NEED1("icmp age required"); 517d8caf56eSAndrey V. Elsukov cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int( 518d8caf56eSAndrey V. Elsukov *av, opt); 519d8caf56eSAndrey V. Elsukov ac--; av++; 520d8caf56eSAndrey V. Elsukov break; 521d8caf56eSAndrey V. Elsukov case TOK_LOG: 522d8caf56eSAndrey V. Elsukov cfg->flags |= NAT64_LOG; 523d8caf56eSAndrey V. Elsukov break; 524d8caf56eSAndrey V. Elsukov case TOK_LOGOFF: 525d8caf56eSAndrey V. Elsukov cfg->flags &= ~NAT64_LOG; 526d8caf56eSAndrey V. Elsukov break; 527*b11efc1eSAndrey V. Elsukov case TOK_PRIVATE: 528*b11efc1eSAndrey V. Elsukov cfg->flags |= NAT64_ALLOW_PRIVATE; 529*b11efc1eSAndrey V. Elsukov break; 530*b11efc1eSAndrey V. Elsukov case TOK_PRIVATEOFF: 531*b11efc1eSAndrey V. Elsukov cfg->flags &= ~NAT64_ALLOW_PRIVATE; 532*b11efc1eSAndrey V. Elsukov break; 533d8caf56eSAndrey V. Elsukov } 534d8caf56eSAndrey V. Elsukov } 535d8caf56eSAndrey V. Elsukov 536d8caf56eSAndrey V. Elsukov /* Check validness */ 537d8caf56eSAndrey V. Elsukov if ((flags & NAT64LSN_HAS_PREFIX4) != NAT64LSN_HAS_PREFIX4) 538d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "prefix4 required"); 539d8caf56eSAndrey V. Elsukov 540d8caf56eSAndrey V. Elsukov olh->count = 1; 541d8caf56eSAndrey V. Elsukov olh->objsize = sizeof(*cfg); 542d8caf56eSAndrey V. Elsukov olh->size = sizeof(buf); 543d8caf56eSAndrey V. Elsukov strlcpy(cfg->name, name, sizeof(cfg->name)); 544d8caf56eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64LSN_CREATE, &olh->opheader, sizeof(buf)) != 0) 545d8caf56eSAndrey V. Elsukov err(EX_OSERR, "nat64lsn instance creation failed"); 546d8caf56eSAndrey V. Elsukov } 547d8caf56eSAndrey V. Elsukov 548d8caf56eSAndrey V. Elsukov /* 549d8caf56eSAndrey V. Elsukov * Configures existing nat64lsn instance 550d8caf56eSAndrey V. Elsukov * ipfw nat64lsn <NAME> config <options> 551d8caf56eSAndrey V. Elsukov * Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ] 552d8caf56eSAndrey V. Elsukov */ 553d8caf56eSAndrey V. Elsukov static void 554d8caf56eSAndrey V. Elsukov nat64lsn_config(const char *name, uint8_t set, int ac, char **av) 555d8caf56eSAndrey V. Elsukov { 556d8caf56eSAndrey V. Elsukov char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64lsn_cfg)]; 557d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_cfg *cfg; 558d8caf56eSAndrey V. Elsukov ipfw_obj_header *oh; 559d8caf56eSAndrey V. Elsukov size_t sz; 560d8caf56eSAndrey V. Elsukov char *opt; 561d8caf56eSAndrey V. Elsukov int tcmd; 562d8caf56eSAndrey V. Elsukov 563d8caf56eSAndrey V. Elsukov if (ac == 0) 564d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "config options required"); 565d8caf56eSAndrey V. Elsukov memset(&buf, 0, sizeof(buf)); 566d8caf56eSAndrey V. Elsukov oh = (ipfw_obj_header *)buf; 567d8caf56eSAndrey V. Elsukov cfg = (ipfw_nat64lsn_cfg *)(oh + 1); 568d8caf56eSAndrey V. Elsukov sz = sizeof(buf); 569d8caf56eSAndrey V. Elsukov 570d8caf56eSAndrey V. Elsukov nat64lsn_fill_ntlv(&oh->ntlv, name, set); 571d8caf56eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, &sz) != 0) 572d8caf56eSAndrey V. Elsukov err(EX_OSERR, "failed to get config for instance %s", name); 573d8caf56eSAndrey V. Elsukov 574d8caf56eSAndrey V. Elsukov while (ac > 0) { 575d8caf56eSAndrey V. Elsukov tcmd = get_token(nat64newcmds, *av, "option"); 576d8caf56eSAndrey V. Elsukov opt = *av; 577d8caf56eSAndrey V. Elsukov ac--; av++; 578d8caf56eSAndrey V. Elsukov 579d8caf56eSAndrey V. Elsukov switch (tcmd) { 580d8caf56eSAndrey V. Elsukov case TOK_MAX_PORTS: 581d8caf56eSAndrey V. Elsukov NEED1("Max per-user ports required"); 582d8caf56eSAndrey V. Elsukov cfg->max_ports = nat64lsn_parse_int(*av, opt); 583d8caf56eSAndrey V. Elsukov ac--; av++; 584d8caf56eSAndrey V. Elsukov break; 585d8caf56eSAndrey V. Elsukov case TOK_JMAXLEN: 586d8caf56eSAndrey V. Elsukov NEED1("job queue length required"); 587d8caf56eSAndrey V. Elsukov cfg->jmaxlen = nat64lsn_parse_int(*av, opt); 588d8caf56eSAndrey V. Elsukov ac--; av++; 589d8caf56eSAndrey V. Elsukov break; 590d8caf56eSAndrey V. Elsukov case TOK_HOST_DEL_AGE: 591d8caf56eSAndrey V. Elsukov NEED1("host delete delay required"); 592d8caf56eSAndrey V. Elsukov cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int( 593d8caf56eSAndrey V. Elsukov *av, opt); 594d8caf56eSAndrey V. Elsukov ac--; av++; 595d8caf56eSAndrey V. Elsukov break; 596d8caf56eSAndrey V. Elsukov case TOK_PG_DEL_AGE: 597d8caf56eSAndrey V. Elsukov NEED1("portgroup delete delay required"); 598d8caf56eSAndrey V. Elsukov cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int( 599d8caf56eSAndrey V. Elsukov *av, opt); 600d8caf56eSAndrey V. Elsukov ac--; av++; 601d8caf56eSAndrey V. Elsukov break; 602d8caf56eSAndrey V. Elsukov case TOK_TCP_SYN_AGE: 603d8caf56eSAndrey V. Elsukov NEED1("tcp syn age required"); 604d8caf56eSAndrey V. Elsukov cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int( 605d8caf56eSAndrey V. Elsukov *av, opt); 606d8caf56eSAndrey V. Elsukov ac--; av++; 607d8caf56eSAndrey V. Elsukov break; 608d8caf56eSAndrey V. Elsukov case TOK_TCP_CLOSE_AGE: 609d8caf56eSAndrey V. Elsukov NEED1("tcp close age required"); 610d8caf56eSAndrey V. Elsukov cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int( 611d8caf56eSAndrey V. Elsukov *av, opt); 612d8caf56eSAndrey V. Elsukov ac--; av++; 613d8caf56eSAndrey V. Elsukov break; 614d8caf56eSAndrey V. Elsukov case TOK_TCP_EST_AGE: 615d8caf56eSAndrey V. Elsukov NEED1("tcp est age required"); 616d8caf56eSAndrey V. Elsukov cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int( 617d8caf56eSAndrey V. Elsukov *av, opt); 618d8caf56eSAndrey V. Elsukov ac--; av++; 619d8caf56eSAndrey V. Elsukov break; 620d8caf56eSAndrey V. Elsukov case TOK_UDP_AGE: 621d8caf56eSAndrey V. Elsukov NEED1("udp age required"); 622d8caf56eSAndrey V. Elsukov cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int( 623d8caf56eSAndrey V. Elsukov *av, opt); 624d8caf56eSAndrey V. Elsukov ac--; av++; 625d8caf56eSAndrey V. Elsukov break; 626d8caf56eSAndrey V. Elsukov case TOK_ICMP_AGE: 627d8caf56eSAndrey V. Elsukov NEED1("icmp age required"); 628d8caf56eSAndrey V. Elsukov cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int( 629d8caf56eSAndrey V. Elsukov *av, opt); 630d8caf56eSAndrey V. Elsukov ac--; av++; 631d8caf56eSAndrey V. Elsukov break; 632d8caf56eSAndrey V. Elsukov case TOK_LOG: 633d8caf56eSAndrey V. Elsukov cfg->flags |= NAT64_LOG; 634d8caf56eSAndrey V. Elsukov break; 635d8caf56eSAndrey V. Elsukov case TOK_LOGOFF: 636d8caf56eSAndrey V. Elsukov cfg->flags &= ~NAT64_LOG; 637d8caf56eSAndrey V. Elsukov break; 638*b11efc1eSAndrey V. Elsukov case TOK_PRIVATE: 639*b11efc1eSAndrey V. Elsukov cfg->flags |= NAT64_ALLOW_PRIVATE; 640*b11efc1eSAndrey V. Elsukov break; 641*b11efc1eSAndrey V. Elsukov case TOK_PRIVATEOFF: 642*b11efc1eSAndrey V. Elsukov cfg->flags &= ~NAT64_ALLOW_PRIVATE; 643*b11efc1eSAndrey V. Elsukov break; 644d8caf56eSAndrey V. Elsukov default: 645d8caf56eSAndrey V. Elsukov errx(EX_USAGE, "Can't change %s option", opt); 646d8caf56eSAndrey V. Elsukov } 647d8caf56eSAndrey V. Elsukov } 648d8caf56eSAndrey V. Elsukov 649d8caf56eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, sizeof(buf)) != 0) 650d8caf56eSAndrey V. Elsukov err(EX_OSERR, "nat64lsn instance configuration failed"); 651d8caf56eSAndrey V. Elsukov } 652d8caf56eSAndrey V. Elsukov 653d8caf56eSAndrey V. Elsukov /* 654d8caf56eSAndrey V. Elsukov * Reset nat64lsn instance statistics specified by @oh->ntlv. 655d8caf56eSAndrey V. Elsukov * Request: [ ipfw_obj_header ] 656d8caf56eSAndrey V. Elsukov */ 657d8caf56eSAndrey V. Elsukov static void 658d8caf56eSAndrey V. Elsukov nat64lsn_reset_stats(const char *name, uint8_t set) 659d8caf56eSAndrey V. Elsukov { 660d8caf56eSAndrey V. Elsukov ipfw_obj_header oh; 661d8caf56eSAndrey V. Elsukov 662d8caf56eSAndrey V. Elsukov memset(&oh, 0, sizeof(oh)); 663d8caf56eSAndrey V. Elsukov nat64lsn_fill_ntlv(&oh.ntlv, name, set); 664d8caf56eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64LSN_RESET_STATS, &oh.opheader, sizeof(oh)) != 0) 665d8caf56eSAndrey V. Elsukov err(EX_OSERR, "failed to reset stats for instance %s", name); 666d8caf56eSAndrey V. Elsukov } 667d8caf56eSAndrey V. Elsukov 668d8caf56eSAndrey V. Elsukov /* 669d8caf56eSAndrey V. Elsukov * Destroys nat64lsn instance specified by @oh->ntlv. 670d8caf56eSAndrey V. Elsukov * Request: [ ipfw_obj_header ] 671d8caf56eSAndrey V. Elsukov */ 672d8caf56eSAndrey V. Elsukov static void 673d8caf56eSAndrey V. Elsukov nat64lsn_destroy(const char *name, uint8_t set) 674d8caf56eSAndrey V. Elsukov { 675d8caf56eSAndrey V. Elsukov ipfw_obj_header oh; 676d8caf56eSAndrey V. Elsukov 677d8caf56eSAndrey V. Elsukov memset(&oh, 0, sizeof(oh)); 678d8caf56eSAndrey V. Elsukov nat64lsn_fill_ntlv(&oh.ntlv, name, set); 679d8caf56eSAndrey V. Elsukov if (do_set3(IP_FW_NAT64LSN_DESTROY, &oh.opheader, sizeof(oh)) != 0) 680d8caf56eSAndrey V. Elsukov err(EX_OSERR, "failed to destroy nat instance %s", name); 681d8caf56eSAndrey V. Elsukov } 682d8caf56eSAndrey V. Elsukov 683d8caf56eSAndrey V. Elsukov /* 684d8caf56eSAndrey V. Elsukov * Get nat64lsn instance statistics. 685d8caf56eSAndrey V. Elsukov * Request: [ ipfw_obj_header ] 686d8caf56eSAndrey V. Elsukov * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ] 687d8caf56eSAndrey V. Elsukov */ 688d8caf56eSAndrey V. Elsukov static int 689d8caf56eSAndrey V. Elsukov nat64lsn_get_stats(const char *name, uint8_t set, 690d8caf56eSAndrey V. Elsukov struct ipfw_nat64lsn_stats *stats) 691d8caf56eSAndrey V. Elsukov { 692d8caf56eSAndrey V. Elsukov ipfw_obj_header *oh; 693d8caf56eSAndrey V. Elsukov ipfw_obj_ctlv *oc; 694d8caf56eSAndrey V. Elsukov size_t sz; 695d8caf56eSAndrey V. Elsukov 696d8caf56eSAndrey V. Elsukov sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats); 697d8caf56eSAndrey V. Elsukov oh = calloc(1, sz); 698d8caf56eSAndrey V. Elsukov nat64lsn_fill_ntlv(&oh->ntlv, name, set); 699d8caf56eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64LSN_STATS, &oh->opheader, &sz) == 0) { 700d8caf56eSAndrey V. Elsukov oc = (ipfw_obj_ctlv *)(oh + 1); 701d8caf56eSAndrey V. Elsukov memcpy(stats, oc + 1, sizeof(*stats)); 702d8caf56eSAndrey V. Elsukov free(oh); 703d8caf56eSAndrey V. Elsukov return (0); 704d8caf56eSAndrey V. Elsukov } 705d8caf56eSAndrey V. Elsukov free(oh); 706d8caf56eSAndrey V. Elsukov return (-1); 707d8caf56eSAndrey V. Elsukov } 708d8caf56eSAndrey V. Elsukov 709d8caf56eSAndrey V. Elsukov static void 710d8caf56eSAndrey V. Elsukov nat64lsn_stats(const char *name, uint8_t set) 711d8caf56eSAndrey V. Elsukov { 712d8caf56eSAndrey V. Elsukov struct ipfw_nat64lsn_stats stats; 713d8caf56eSAndrey V. Elsukov 714d8caf56eSAndrey V. Elsukov if (nat64lsn_get_stats(name, set, &stats) != 0) 715d8caf56eSAndrey V. Elsukov err(EX_OSERR, "Error retrieving stats"); 716d8caf56eSAndrey V. Elsukov 717c5e85276SAndrey V. Elsukov if (co.use_set != 0 || set != 0) 718c5e85276SAndrey V. Elsukov printf("set %u ", set); 719c5e85276SAndrey V. Elsukov printf("nat64lsn %s\n", name); 720c5e85276SAndrey V. Elsukov printf("\t%ju packets translated from IPv6 to IPv4\n", 721c5e85276SAndrey V. Elsukov (uintmax_t)stats.opcnt64); 722c5e85276SAndrey V. Elsukov printf("\t%ju packets translated from IPv4 to IPv6\n", 723c5e85276SAndrey V. Elsukov (uintmax_t)stats.opcnt46); 724c5e85276SAndrey V. Elsukov printf("\t%ju IPv6 fragments created\n", 725c5e85276SAndrey V. Elsukov (uintmax_t)stats.ofrags); 726c5e85276SAndrey V. Elsukov printf("\t%ju IPv4 fragments received\n", 727c5e85276SAndrey V. Elsukov (uintmax_t)stats.ifrags); 728c5e85276SAndrey V. Elsukov printf("\t%ju output packets dropped due to no bufs, etc.\n", 729c5e85276SAndrey V. Elsukov (uintmax_t)stats.oerrors); 730c5e85276SAndrey V. Elsukov printf("\t%ju output packets discarded due to no IPv4 route\n", 731c5e85276SAndrey V. Elsukov (uintmax_t)stats.noroute4); 732c5e85276SAndrey V. Elsukov printf("\t%ju output packets discarded due to no IPv6 route\n", 733c5e85276SAndrey V. Elsukov (uintmax_t)stats.noroute6); 734c5e85276SAndrey V. Elsukov printf("\t%ju packets discarded due to unsupported protocol\n", 735c5e85276SAndrey V. Elsukov (uintmax_t)stats.noproto); 736c5e85276SAndrey V. Elsukov printf("\t%ju packets discarded due to memory allocation problems\n", 737c5e85276SAndrey V. Elsukov (uintmax_t)stats.nomem); 738c5e85276SAndrey V. Elsukov printf("\t%ju packets discarded due to some errors\n", 739c5e85276SAndrey V. Elsukov (uintmax_t)stats.dropped); 740c5e85276SAndrey V. Elsukov printf("\t%ju packets not matched with IPv4 prefix\n", 741c5e85276SAndrey V. Elsukov (uintmax_t)stats.nomatch4); 742d8caf56eSAndrey V. Elsukov 743c5e85276SAndrey V. Elsukov printf("\t%ju mbufs queued for post processing\n", 744c5e85276SAndrey V. Elsukov (uintmax_t)stats.jreinjected); 745c5e85276SAndrey V. Elsukov printf("\t%ju times the job queue was processed\n", 746c5e85276SAndrey V. Elsukov (uintmax_t)stats.jcalls); 747c5e85276SAndrey V. Elsukov printf("\t%ju job requests queued\n", 748c5e85276SAndrey V. Elsukov (uintmax_t)stats.jrequests); 749c5e85276SAndrey V. Elsukov printf("\t%ju job requests queue limit reached\n", 750c5e85276SAndrey V. Elsukov (uintmax_t)stats.jmaxlen); 751c5e85276SAndrey V. Elsukov printf("\t%ju job requests failed due to memory allocation problems\n", 752c5e85276SAndrey V. Elsukov (uintmax_t)stats.jnomem); 753c5e85276SAndrey V. Elsukov 754c5e85276SAndrey V. Elsukov printf("\t%ju hosts allocated\n", (uintmax_t)stats.hostcount); 755c5e85276SAndrey V. Elsukov printf("\t%ju hosts requested\n", (uintmax_t)stats.jhostsreq); 756c5e85276SAndrey V. Elsukov printf("\t%ju host requests failed\n", (uintmax_t)stats.jhostfails); 757c5e85276SAndrey V. Elsukov 758c5e85276SAndrey V. Elsukov printf("\t%ju portgroups requested\n", (uintmax_t)stats.jportreq); 759c5e85276SAndrey V. Elsukov printf("\t%ju portgroups allocated\n", (uintmax_t)stats.spgcreated); 760c5e85276SAndrey V. Elsukov printf("\t%ju portgroups deleted\n", (uintmax_t)stats.spgdeleted); 761c5e85276SAndrey V. Elsukov printf("\t%ju portgroup requests failed\n", 762c5e85276SAndrey V. Elsukov (uintmax_t)stats.jportfails); 763c5e85276SAndrey V. Elsukov printf("\t%ju portgroups allocated for TCP\n", 764c5e85276SAndrey V. Elsukov (uintmax_t)stats.tcpchunks); 765c5e85276SAndrey V. Elsukov printf("\t%ju portgroups allocated for UDP\n", 766c5e85276SAndrey V. Elsukov (uintmax_t)stats.udpchunks); 767c5e85276SAndrey V. Elsukov printf("\t%ju portgroups allocated for ICMP\n", 768c5e85276SAndrey V. Elsukov (uintmax_t)stats.icmpchunks); 769c5e85276SAndrey V. Elsukov 770c5e85276SAndrey V. Elsukov printf("\t%ju states created\n", (uintmax_t)stats.screated); 771c5e85276SAndrey V. Elsukov printf("\t%ju states deleted\n", (uintmax_t)stats.sdeleted); 772d8caf56eSAndrey V. Elsukov } 773d8caf56eSAndrey V. Elsukov 774d8caf56eSAndrey V. Elsukov static int 775d8caf56eSAndrey V. Elsukov nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set) 776d8caf56eSAndrey V. Elsukov { 777d8caf56eSAndrey V. Elsukov char abuf[INET6_ADDRSTRLEN]; 778d8caf56eSAndrey V. Elsukov 779d8caf56eSAndrey V. Elsukov if (name != NULL && strcmp(cfg->name, name) != 0) 780d8caf56eSAndrey V. Elsukov return (ESRCH); 781d8caf56eSAndrey V. Elsukov 782d8caf56eSAndrey V. Elsukov if (co.use_set != 0 && cfg->set != set) 783d8caf56eSAndrey V. Elsukov return (ESRCH); 784d8caf56eSAndrey V. Elsukov 785d8caf56eSAndrey V. Elsukov if (co.use_set != 0 || cfg->set != 0) 786d8caf56eSAndrey V. Elsukov printf("set %u ", cfg->set); 787d8caf56eSAndrey V. Elsukov inet_ntop(AF_INET, &cfg->prefix4, abuf, sizeof(abuf)); 788d8caf56eSAndrey V. Elsukov printf("nat64lsn %s prefix4 %s/%u", cfg->name, abuf, cfg->plen4); 789d8caf56eSAndrey V. Elsukov inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf)); 790d8caf56eSAndrey V. Elsukov printf(" prefix6 %s/%u", abuf, cfg->plen6); 791782360deSAndrey V. Elsukov #if 0 792d8caf56eSAndrey V. Elsukov printf("agg_len %u agg_count %u ", cfg->agg_prefix_len, 793d8caf56eSAndrey V. Elsukov cfg->agg_prefix_max); 794d8caf56eSAndrey V. Elsukov if (cfg->min_port != NAT64LSN_PORT_MIN || 795d8caf56eSAndrey V. Elsukov cfg->max_port != NAT64LSN_PORT_MAX) 796d8caf56eSAndrey V. Elsukov printf(" port_range %u:%u", cfg->min_port, cfg->max_port); 797d8caf56eSAndrey V. Elsukov if (cfg->jmaxlen != NAT64LSN_JMAXLEN) 798d8caf56eSAndrey V. Elsukov printf(" jmaxlen %u ", cfg->jmaxlen); 799d8caf56eSAndrey V. Elsukov #endif 800d8caf56eSAndrey V. Elsukov if (cfg->max_ports != NAT64LSN_MAX_PORTS) 801d8caf56eSAndrey V. Elsukov printf(" max_ports %u", cfg->max_ports); 802d8caf56eSAndrey V. Elsukov if (cfg->nh_delete_delay != NAT64LSN_HOST_AGE) 803d8caf56eSAndrey V. Elsukov printf(" host_del_age %u", cfg->nh_delete_delay); 804d8caf56eSAndrey V. Elsukov if (cfg->pg_delete_delay != NAT64LSN_PG_AGE) 805d8caf56eSAndrey V. Elsukov printf(" pg_del_age %u ", cfg->pg_delete_delay); 806d8caf56eSAndrey V. Elsukov if (cfg->st_syn_ttl != NAT64LSN_TCP_SYN_AGE) 807d8caf56eSAndrey V. Elsukov printf(" tcp_syn_age %u", cfg->st_syn_ttl); 808d8caf56eSAndrey V. Elsukov if (cfg->st_close_ttl != NAT64LSN_TCP_FIN_AGE) 809d8caf56eSAndrey V. Elsukov printf(" tcp_close_age %u", cfg->st_close_ttl); 810d8caf56eSAndrey V. Elsukov if (cfg->st_estab_ttl != NAT64LSN_TCP_EST_AGE) 811d8caf56eSAndrey V. Elsukov printf(" tcp_est_age %u", cfg->st_estab_ttl); 812d8caf56eSAndrey V. Elsukov if (cfg->st_udp_ttl != NAT64LSN_UDP_AGE) 813d8caf56eSAndrey V. Elsukov printf(" udp_age %u", cfg->st_udp_ttl); 814d8caf56eSAndrey V. Elsukov if (cfg->st_icmp_ttl != NAT64LSN_ICMP_AGE) 815d8caf56eSAndrey V. Elsukov printf(" icmp_age %u", cfg->st_icmp_ttl); 816d8caf56eSAndrey V. Elsukov if (cfg->flags & NAT64_LOG) 817d8caf56eSAndrey V. Elsukov printf(" log"); 818*b11efc1eSAndrey V. Elsukov if (cfg->flags & NAT64_ALLOW_PRIVATE) 819*b11efc1eSAndrey V. Elsukov printf(" allow_private"); 820d8caf56eSAndrey V. Elsukov printf("\n"); 821d8caf56eSAndrey V. Elsukov return (0); 822d8caf56eSAndrey V. Elsukov } 823d8caf56eSAndrey V. Elsukov 824d8caf56eSAndrey V. Elsukov static int 825d8caf56eSAndrey V. Elsukov nat64lsn_destroy_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set) 826d8caf56eSAndrey V. Elsukov { 827d8caf56eSAndrey V. Elsukov 828d8caf56eSAndrey V. Elsukov if (co.use_set != 0 && cfg->set != set) 829d8caf56eSAndrey V. Elsukov return (ESRCH); 830d8caf56eSAndrey V. Elsukov 831d8caf56eSAndrey V. Elsukov nat64lsn_destroy(cfg->name, cfg->set); 832d8caf56eSAndrey V. Elsukov return (0); 833d8caf56eSAndrey V. Elsukov } 834d8caf56eSAndrey V. Elsukov 835d8caf56eSAndrey V. Elsukov 836d8caf56eSAndrey V. Elsukov /* 837d8caf56eSAndrey V. Elsukov * Compare nat64lsn instances names. 838d8caf56eSAndrey V. Elsukov * Honor number comparison. 839d8caf56eSAndrey V. Elsukov */ 840d8caf56eSAndrey V. Elsukov static int 841d8caf56eSAndrey V. Elsukov nat64name_cmp(const void *a, const void *b) 842d8caf56eSAndrey V. Elsukov { 843d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_cfg *ca, *cb; 844d8caf56eSAndrey V. Elsukov 845d8caf56eSAndrey V. Elsukov ca = (ipfw_nat64lsn_cfg *)a; 846d8caf56eSAndrey V. Elsukov cb = (ipfw_nat64lsn_cfg *)b; 847d8caf56eSAndrey V. Elsukov 848d8caf56eSAndrey V. Elsukov if (ca->set > cb->set) 849d8caf56eSAndrey V. Elsukov return (1); 850d8caf56eSAndrey V. Elsukov else if (ca->set < cb->set) 851d8caf56eSAndrey V. Elsukov return (-1); 852d8caf56eSAndrey V. Elsukov return (stringnum_cmp(ca->name, cb->name)); 853d8caf56eSAndrey V. Elsukov } 854d8caf56eSAndrey V. Elsukov 855d8caf56eSAndrey V. Elsukov /* 856d8caf56eSAndrey V. Elsukov * Retrieves nat64lsn instance list from kernel, 857d8caf56eSAndrey V. Elsukov * optionally sorts it and calls requested function for each instance. 858d8caf56eSAndrey V. Elsukov * 859d8caf56eSAndrey V. Elsukov * Request: [ ipfw_obj_lheader ] 860d8caf56eSAndrey V. Elsukov * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ] 861d8caf56eSAndrey V. Elsukov */ 862d8caf56eSAndrey V. Elsukov static int 863d8caf56eSAndrey V. Elsukov nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set, int sort) 864d8caf56eSAndrey V. Elsukov { 865d8caf56eSAndrey V. Elsukov ipfw_obj_lheader *olh; 866d8caf56eSAndrey V. Elsukov ipfw_nat64lsn_cfg *cfg; 867d8caf56eSAndrey V. Elsukov size_t sz; 868d8caf56eSAndrey V. Elsukov int i, error; 869d8caf56eSAndrey V. Elsukov 870d8caf56eSAndrey V. Elsukov /* Start with reasonable default */ 871d8caf56eSAndrey V. Elsukov sz = sizeof(*olh) + 16 * sizeof(ipfw_nat64lsn_cfg); 872d8caf56eSAndrey V. Elsukov 873d8caf56eSAndrey V. Elsukov for (;;) { 874d8caf56eSAndrey V. Elsukov if ((olh = calloc(1, sz)) == NULL) 875d8caf56eSAndrey V. Elsukov return (ENOMEM); 876d8caf56eSAndrey V. Elsukov 877d8caf56eSAndrey V. Elsukov olh->size = sz; 878d8caf56eSAndrey V. Elsukov if (do_get3(IP_FW_NAT64LSN_LIST, &olh->opheader, &sz) != 0) { 879d8caf56eSAndrey V. Elsukov sz = olh->size; 880d8caf56eSAndrey V. Elsukov free(olh); 881d8caf56eSAndrey V. Elsukov if (errno != ENOMEM) 882d8caf56eSAndrey V. Elsukov return (errno); 883d8caf56eSAndrey V. Elsukov continue; 884d8caf56eSAndrey V. Elsukov } 885d8caf56eSAndrey V. Elsukov 886d8caf56eSAndrey V. Elsukov if (sort != 0) 887d8caf56eSAndrey V. Elsukov qsort(olh + 1, olh->count, olh->objsize, 888d8caf56eSAndrey V. Elsukov nat64name_cmp); 889d8caf56eSAndrey V. Elsukov 890d8caf56eSAndrey V. Elsukov cfg = (ipfw_nat64lsn_cfg *)(olh + 1); 891d8caf56eSAndrey V. Elsukov for (i = 0; i < olh->count; i++) { 892d8caf56eSAndrey V. Elsukov error = f(cfg, name, set); /* Ignore errors for now */ 893d8caf56eSAndrey V. Elsukov cfg = (ipfw_nat64lsn_cfg *)((caddr_t)cfg + 894d8caf56eSAndrey V. Elsukov olh->objsize); 895d8caf56eSAndrey V. Elsukov } 896d8caf56eSAndrey V. Elsukov free(olh); 897d8caf56eSAndrey V. Elsukov break; 898d8caf56eSAndrey V. Elsukov } 899d8caf56eSAndrey V. Elsukov return (0); 900d8caf56eSAndrey V. Elsukov } 901d8caf56eSAndrey V. Elsukov 902