xref: /f-stack/tools/ipfw/nat64lsn.c (revision d4a07e70)
122ce4affSfengbojiang /*-
222ce4affSfengbojiang  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
322ce4affSfengbojiang  *
422ce4affSfengbojiang  * Copyright (c) 2015-2019 Yandex LLC
522ce4affSfengbojiang  * Copyright (c) 2015-2016 Alexander V. Chernikov <[email protected]>
622ce4affSfengbojiang  * Copyright (c) 2015-2019 Andrey V. Elsukov <[email protected]>
722ce4affSfengbojiang  *
822ce4affSfengbojiang  * Redistribution and use in source and binary forms, with or without
922ce4affSfengbojiang  * modification, are permitted provided that the following conditions
1022ce4affSfengbojiang  * are met:
1122ce4affSfengbojiang  *
1222ce4affSfengbojiang  * 1. Redistributions of source code must retain the above copyright
1322ce4affSfengbojiang  *    notice, this list of conditions and the following disclaimer.
1422ce4affSfengbojiang  * 2. Redistributions in binary form must reproduce the above copyright
1522ce4affSfengbojiang  *    notice, this list of conditions and the following disclaimer in the
1622ce4affSfengbojiang  *    documentation and/or other materials provided with the distribution.
1722ce4affSfengbojiang  *
1822ce4affSfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1922ce4affSfengbojiang  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2022ce4affSfengbojiang  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2122ce4affSfengbojiang  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2222ce4affSfengbojiang  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2322ce4affSfengbojiang  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2422ce4affSfengbojiang  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2522ce4affSfengbojiang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2622ce4affSfengbojiang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2722ce4affSfengbojiang  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2822ce4affSfengbojiang  */
2922ce4affSfengbojiang 
3022ce4affSfengbojiang #include <sys/cdefs.h>
3122ce4affSfengbojiang __FBSDID("$FreeBSD$");
3222ce4affSfengbojiang 
3322ce4affSfengbojiang #include <sys/types.h>
3422ce4affSfengbojiang #include <sys/socket.h>
3522ce4affSfengbojiang 
3622ce4affSfengbojiang #include "ipfw2.h"
3722ce4affSfengbojiang 
3822ce4affSfengbojiang #include <ctype.h>
3922ce4affSfengbojiang #include <err.h>
4022ce4affSfengbojiang #include <errno.h>
4122ce4affSfengbojiang #include <inttypes.h>
4222ce4affSfengbojiang #include <netdb.h>
4322ce4affSfengbojiang #include <stdio.h>
4422ce4affSfengbojiang #include <stdlib.h>
4522ce4affSfengbojiang #include <string.h>
4622ce4affSfengbojiang #include <sysexits.h>
4722ce4affSfengbojiang 
4822ce4affSfengbojiang #include <net/if.h>
4922ce4affSfengbojiang #include <netinet/in.h>
5022ce4affSfengbojiang #include <netinet/ip_fw.h>
5122ce4affSfengbojiang #include <netinet6/ip_fw_nat64.h>
5222ce4affSfengbojiang #include <arpa/inet.h>
5322ce4affSfengbojiang 
54*d4a07e70Sfengbojiang #ifdef FSTACK
55*d4a07e70Sfengbojiang #ifndef __unused
56*d4a07e70Sfengbojiang #define __unused __attribute__((__unused__))
57*d4a07e70Sfengbojiang #endif
58*d4a07e70Sfengbojiang #endif
59*d4a07e70Sfengbojiang 
6022ce4affSfengbojiang static void nat64lsn_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name,
6122ce4affSfengbojiang     uint8_t set);
6222ce4affSfengbojiang typedef int (nat64lsn_cb_t)(ipfw_nat64lsn_cfg *cfg, const char *name,
6322ce4affSfengbojiang     uint8_t set);
6422ce4affSfengbojiang static int nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set,
6522ce4affSfengbojiang     int sort);
6622ce4affSfengbojiang 
6722ce4affSfengbojiang static void nat64lsn_create(const char *name, uint8_t set, int ac, char **av);
6822ce4affSfengbojiang static void nat64lsn_config(const char *name, uint8_t set, int ac, char **av);
6922ce4affSfengbojiang static void nat64lsn_destroy(const char *name, uint8_t set);
7022ce4affSfengbojiang static void nat64lsn_stats(const char *name, uint8_t set);
7122ce4affSfengbojiang static void nat64lsn_reset_stats(const char *name, uint8_t set);
7222ce4affSfengbojiang static int nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name,
7322ce4affSfengbojiang     uint8_t set);
7422ce4affSfengbojiang static int nat64lsn_destroy_cb(ipfw_nat64lsn_cfg *cfg, const char *name,
7522ce4affSfengbojiang     uint8_t set);
7622ce4affSfengbojiang static int nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name,
7722ce4affSfengbojiang     uint8_t set);
7822ce4affSfengbojiang 
7922ce4affSfengbojiang static struct _s_x nat64cmds[] = {
8022ce4affSfengbojiang       { "create",	TOK_CREATE },
8122ce4affSfengbojiang       { "config",	TOK_CONFIG },
8222ce4affSfengbojiang       { "destroy",	TOK_DESTROY },
8322ce4affSfengbojiang       { "list",		TOK_LIST },
8422ce4affSfengbojiang       { "show",		TOK_LIST },
8522ce4affSfengbojiang       { "stats",	TOK_STATS },
8622ce4affSfengbojiang       { NULL, 0 }
8722ce4affSfengbojiang };
8822ce4affSfengbojiang 
8922ce4affSfengbojiang static uint64_t
nat64lsn_print_states(void * buf)9022ce4affSfengbojiang nat64lsn_print_states(void *buf)
9122ce4affSfengbojiang {
9222ce4affSfengbojiang 	char s[INET6_ADDRSTRLEN], a[INET_ADDRSTRLEN], f[INET_ADDRSTRLEN];
9322ce4affSfengbojiang 	const char *proto;
9422ce4affSfengbojiang 	char sflags[4], *sf;
9522ce4affSfengbojiang 	ipfw_obj_header *oh;
9622ce4affSfengbojiang 	ipfw_obj_data *od;
9722ce4affSfengbojiang 	ipfw_nat64lsn_stg_v1 *stg;
9822ce4affSfengbojiang 	ipfw_nat64lsn_state_v1 *ste;
9922ce4affSfengbojiang 	uint64_t next_idx;
10022ce4affSfengbojiang 	uint32_t i;
10122ce4affSfengbojiang 	int sz;
10222ce4affSfengbojiang 
10322ce4affSfengbojiang 	oh = (ipfw_obj_header *)buf;
10422ce4affSfengbojiang 	od = (ipfw_obj_data *)(oh + 1);
10522ce4affSfengbojiang 	stg = (ipfw_nat64lsn_stg_v1 *)(od + 1);
10622ce4affSfengbojiang 	sz = od->head.length - sizeof(*od);
10722ce4affSfengbojiang 	next_idx = 0;
10822ce4affSfengbojiang 	proto = NULL;
10922ce4affSfengbojiang 	while (sz > 0 && next_idx != 0xFF) {
11022ce4affSfengbojiang 		next_idx = stg->next.index;
11122ce4affSfengbojiang 		sz -= sizeof(*stg);
11222ce4affSfengbojiang 		if (stg->count == 0) {
11322ce4affSfengbojiang 			stg++;
11422ce4affSfengbojiang 			continue;
11522ce4affSfengbojiang 		}
11622ce4affSfengbojiang 		/*
11722ce4affSfengbojiang 		 * NOTE: addresses are in network byte order,
11822ce4affSfengbojiang 		 * ports are in host byte order.
11922ce4affSfengbojiang 		 */
12022ce4affSfengbojiang 		inet_ntop(AF_INET, &stg->alias4, a, sizeof(a));
12122ce4affSfengbojiang 		ste = (ipfw_nat64lsn_state_v1 *)(stg + 1);
12222ce4affSfengbojiang 		for (i = 0; i < stg->count && sz > 0; i++) {
12322ce4affSfengbojiang 			sf = sflags;
12422ce4affSfengbojiang 			inet_ntop(AF_INET6, &ste->host6, s, sizeof(s));
12522ce4affSfengbojiang 			inet_ntop(AF_INET, &ste->daddr, f, sizeof(f));
12622ce4affSfengbojiang 			switch (ste->proto) {
12722ce4affSfengbojiang 			case IPPROTO_TCP:
12822ce4affSfengbojiang 				proto = "TCP";
12922ce4affSfengbojiang 				if (ste->flags & 0x02)
13022ce4affSfengbojiang 					*sf++ = 'S';
13122ce4affSfengbojiang 				if (ste->flags & 0x04)
13222ce4affSfengbojiang 					*sf++ = 'E';
13322ce4affSfengbojiang 				if (ste->flags & 0x01)
13422ce4affSfengbojiang 					*sf++ = 'F';
13522ce4affSfengbojiang 				break;
13622ce4affSfengbojiang 			case IPPROTO_UDP:
13722ce4affSfengbojiang 				proto = "UDP";
13822ce4affSfengbojiang 				break;
13922ce4affSfengbojiang 			case IPPROTO_ICMP:
14022ce4affSfengbojiang 				proto = "ICMPv6";
14122ce4affSfengbojiang 				break;
14222ce4affSfengbojiang 			}
14322ce4affSfengbojiang 			*sf = '\0';
14422ce4affSfengbojiang 			switch (ste->proto) {
14522ce4affSfengbojiang 			case IPPROTO_TCP:
14622ce4affSfengbojiang 			case IPPROTO_UDP:
14722ce4affSfengbojiang 				printf("%s:%d\t%s:%d\t%s\t%s\t%d\t%s:%d\n",
14822ce4affSfengbojiang 				    s, ste->sport, a, ste->aport, proto,
14922ce4affSfengbojiang 				    sflags, ste->idle, f, ste->dport);
15022ce4affSfengbojiang 				break;
15122ce4affSfengbojiang 			case IPPROTO_ICMP:
15222ce4affSfengbojiang 				printf("%s\t%s\t%s\t\t%d\t%s\n",
15322ce4affSfengbojiang 				    s, a, proto, ste->idle, f);
15422ce4affSfengbojiang 				break;
15522ce4affSfengbojiang 			default:
15622ce4affSfengbojiang 				printf("%s\t%s\t%d\t\t%d\t%s\n",
15722ce4affSfengbojiang 				    s, a, ste->proto, ste->idle, f);
15822ce4affSfengbojiang 			}
15922ce4affSfengbojiang 			ste++;
16022ce4affSfengbojiang 			sz -= sizeof(*ste);
16122ce4affSfengbojiang 		}
16222ce4affSfengbojiang 		stg = (ipfw_nat64lsn_stg_v1 *)ste;
16322ce4affSfengbojiang 	}
16422ce4affSfengbojiang 	return (next_idx);
16522ce4affSfengbojiang }
16622ce4affSfengbojiang 
16722ce4affSfengbojiang static int
nat64lsn_states_cb(ipfw_nat64lsn_cfg * cfg,const char * name,uint8_t set)16822ce4affSfengbojiang nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set)
16922ce4affSfengbojiang {
17022ce4affSfengbojiang 	ipfw_obj_header *oh;
17122ce4affSfengbojiang 	ipfw_obj_data *od;
17222ce4affSfengbojiang 	void *buf;
17322ce4affSfengbojiang 	uint64_t next_idx;
17422ce4affSfengbojiang 	size_t sz;
17522ce4affSfengbojiang 
17622ce4affSfengbojiang 	if (name != NULL && strcmp(cfg->name, name) != 0)
17722ce4affSfengbojiang 		return (ESRCH);
17822ce4affSfengbojiang 
17922ce4affSfengbojiang 	if (set != 0 && cfg->set != set)
18022ce4affSfengbojiang 		return (ESRCH);
18122ce4affSfengbojiang 
18222ce4affSfengbojiang 	next_idx = 0;
18322ce4affSfengbojiang 	sz = 4096;
18422ce4affSfengbojiang 	if ((buf = calloc(1, sz)) == NULL)
18522ce4affSfengbojiang 		err(EX_OSERR, NULL);
18622ce4affSfengbojiang 	do {
18722ce4affSfengbojiang 		oh = (ipfw_obj_header *)buf;
18822ce4affSfengbojiang 		oh->opheader.version = 1; /* Force using ov new API */
18922ce4affSfengbojiang 		od = (ipfw_obj_data *)(oh + 1);
19022ce4affSfengbojiang 		nat64lsn_fill_ntlv(&oh->ntlv, cfg->name, set);
19122ce4affSfengbojiang 		od->head.type = IPFW_TLV_OBJDATA;
19222ce4affSfengbojiang 		od->head.length = sizeof(*od) + sizeof(next_idx);
19322ce4affSfengbojiang 		*((uint64_t *)(od + 1)) = next_idx;
19422ce4affSfengbojiang 		if (do_get3(IP_FW_NAT64LSN_LIST_STATES, &oh->opheader, &sz))
19522ce4affSfengbojiang 			err(EX_OSERR, "Error reading nat64lsn states");
19622ce4affSfengbojiang 		next_idx = nat64lsn_print_states(buf);
19722ce4affSfengbojiang 		sz = 4096;
19822ce4affSfengbojiang 		memset(buf, 0, sz);
19922ce4affSfengbojiang 	} while (next_idx != 0xFF);
20022ce4affSfengbojiang 
20122ce4affSfengbojiang 	free(buf);
20222ce4affSfengbojiang 	return (0);
20322ce4affSfengbojiang }
20422ce4affSfengbojiang 
20522ce4affSfengbojiang static struct _s_x nat64statscmds[] = {
20622ce4affSfengbojiang       { "reset",	TOK_RESET },
20722ce4affSfengbojiang       { NULL, 0 }
20822ce4affSfengbojiang };
20922ce4affSfengbojiang 
21022ce4affSfengbojiang static void
ipfw_nat64lsn_stats_handler(const char * name,uint8_t set,int ac,char * av[])21122ce4affSfengbojiang ipfw_nat64lsn_stats_handler(const char *name, uint8_t set, int ac, char *av[])
21222ce4affSfengbojiang {
21322ce4affSfengbojiang 	int tcmd;
21422ce4affSfengbojiang 
21522ce4affSfengbojiang 	if (ac == 0) {
21622ce4affSfengbojiang 		nat64lsn_stats(name, set);
21722ce4affSfengbojiang 		return;
21822ce4affSfengbojiang 	}
21922ce4affSfengbojiang 	NEED1("nat64lsn stats needs command");
22022ce4affSfengbojiang 	tcmd = get_token(nat64statscmds, *av, "nat64lsn stats command");
22122ce4affSfengbojiang 	switch (tcmd) {
22222ce4affSfengbojiang 	case TOK_RESET:
22322ce4affSfengbojiang 		nat64lsn_reset_stats(name, set);
22422ce4affSfengbojiang 	}
22522ce4affSfengbojiang }
22622ce4affSfengbojiang 
22722ce4affSfengbojiang static struct _s_x nat64listcmds[] = {
22822ce4affSfengbojiang       { "states",	TOK_STATES },
22922ce4affSfengbojiang       { "config",	TOK_CONFIG },
23022ce4affSfengbojiang       { NULL, 0 }
23122ce4affSfengbojiang };
23222ce4affSfengbojiang 
23322ce4affSfengbojiang static void
ipfw_nat64lsn_list_handler(const char * name,uint8_t set,int ac,char * av[])23422ce4affSfengbojiang ipfw_nat64lsn_list_handler(const char *name, uint8_t set, int ac, char *av[])
23522ce4affSfengbojiang {
23622ce4affSfengbojiang 	int tcmd;
23722ce4affSfengbojiang 
23822ce4affSfengbojiang 	if (ac == 0) {
23922ce4affSfengbojiang 		nat64lsn_foreach(nat64lsn_show_cb, name, set, 1);
24022ce4affSfengbojiang 		return;
24122ce4affSfengbojiang 	}
24222ce4affSfengbojiang 	NEED1("nat64lsn list needs command");
24322ce4affSfengbojiang 	tcmd = get_token(nat64listcmds, *av, "nat64lsn list command");
24422ce4affSfengbojiang 	switch (tcmd) {
24522ce4affSfengbojiang 	case TOK_STATES:
24622ce4affSfengbojiang 		nat64lsn_foreach(nat64lsn_states_cb, name, set, 1);
24722ce4affSfengbojiang 		break;
24822ce4affSfengbojiang 	case TOK_CONFIG:
24922ce4affSfengbojiang 		nat64lsn_foreach(nat64lsn_show_cb, name, set, 1);
25022ce4affSfengbojiang 	}
25122ce4affSfengbojiang }
25222ce4affSfengbojiang 
25322ce4affSfengbojiang /*
25422ce4affSfengbojiang  * This one handles all nat64lsn-related commands
25522ce4affSfengbojiang  *	ipfw [set N] nat64lsn NAME {create | config} ...
25622ce4affSfengbojiang  *	ipfw [set N] nat64lsn NAME stats
25722ce4affSfengbojiang  *	ipfw [set N] nat64lsn {NAME | all} destroy
25822ce4affSfengbojiang  *	ipfw [set N] nat64lsn {NAME | all} {list | show} [config | states]
25922ce4affSfengbojiang  */
26022ce4affSfengbojiang #define	nat64lsn_check_name	table_check_name
26122ce4affSfengbojiang void
ipfw_nat64lsn_handler(int ac,char * av[])26222ce4affSfengbojiang ipfw_nat64lsn_handler(int ac, char *av[])
26322ce4affSfengbojiang {
26422ce4affSfengbojiang 	const char *name;
26522ce4affSfengbojiang 	int tcmd;
26622ce4affSfengbojiang 	uint8_t set;
26722ce4affSfengbojiang 
26822ce4affSfengbojiang 	if (g_co.use_set != 0)
26922ce4affSfengbojiang 		set = g_co.use_set - 1;
27022ce4affSfengbojiang 	else
27122ce4affSfengbojiang 		set = 0;
27222ce4affSfengbojiang 	ac--; av++;
27322ce4affSfengbojiang 
27422ce4affSfengbojiang 	NEED1("nat64lsn needs instance name");
27522ce4affSfengbojiang 	name = *av;
27622ce4affSfengbojiang 	if (nat64lsn_check_name(name) != 0) {
27722ce4affSfengbojiang 		if (strcmp(name, "all") == 0)
27822ce4affSfengbojiang 			name = NULL;
27922ce4affSfengbojiang 		else
28022ce4affSfengbojiang 			errx(EX_USAGE, "nat64lsn instance name %s is invalid",
28122ce4affSfengbojiang 			    name);
28222ce4affSfengbojiang 	}
28322ce4affSfengbojiang 	ac--; av++;
28422ce4affSfengbojiang 	NEED1("nat64lsn needs command");
28522ce4affSfengbojiang 
28622ce4affSfengbojiang 	tcmd = get_token(nat64cmds, *av, "nat64lsn command");
28722ce4affSfengbojiang 	if (name == NULL && tcmd != TOK_DESTROY && tcmd != TOK_LIST)
28822ce4affSfengbojiang 		errx(EX_USAGE, "nat64lsn instance name required");
28922ce4affSfengbojiang 	switch (tcmd) {
29022ce4affSfengbojiang 	case TOK_CREATE:
29122ce4affSfengbojiang 		ac--; av++;
29222ce4affSfengbojiang 		nat64lsn_create(name, set, ac, av);
29322ce4affSfengbojiang 		break;
29422ce4affSfengbojiang 	case TOK_CONFIG:
29522ce4affSfengbojiang 		ac--; av++;
29622ce4affSfengbojiang 		nat64lsn_config(name, set, ac, av);
29722ce4affSfengbojiang 		break;
29822ce4affSfengbojiang 	case TOK_LIST:
29922ce4affSfengbojiang 		ac--; av++;
30022ce4affSfengbojiang 		ipfw_nat64lsn_list_handler(name, set, ac, av);
30122ce4affSfengbojiang 		break;
30222ce4affSfengbojiang 	case TOK_DESTROY:
30322ce4affSfengbojiang 		if (name == NULL)
30422ce4affSfengbojiang 			nat64lsn_foreach(nat64lsn_destroy_cb, NULL, set, 0);
30522ce4affSfengbojiang 		else
30622ce4affSfengbojiang 			nat64lsn_destroy(name, set);
30722ce4affSfengbojiang 		break;
30822ce4affSfengbojiang 	case TOK_STATS:
30922ce4affSfengbojiang 		ac--; av++;
31022ce4affSfengbojiang 		ipfw_nat64lsn_stats_handler(name, set, ac, av);
31122ce4affSfengbojiang 	}
31222ce4affSfengbojiang }
31322ce4affSfengbojiang 
31422ce4affSfengbojiang static void
nat64lsn_fill_ntlv(ipfw_obj_ntlv * ntlv,const char * name,uint8_t set)31522ce4affSfengbojiang nat64lsn_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set)
31622ce4affSfengbojiang {
31722ce4affSfengbojiang 
31822ce4affSfengbojiang 	ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */
31922ce4affSfengbojiang 	ntlv->head.length = sizeof(ipfw_obj_ntlv);
32022ce4affSfengbojiang 	ntlv->idx = 1;
32122ce4affSfengbojiang 	ntlv->set = set;
32222ce4affSfengbojiang 	strlcpy(ntlv->name, name, sizeof(ntlv->name));
32322ce4affSfengbojiang }
32422ce4affSfengbojiang 
32522ce4affSfengbojiang static void
nat64lsn_apply_mask(int af,void * prefix,uint16_t plen)32622ce4affSfengbojiang nat64lsn_apply_mask(int af, void *prefix, uint16_t plen)
32722ce4affSfengbojiang {
32822ce4affSfengbojiang 	struct in6_addr mask6, *p6;
32922ce4affSfengbojiang 	struct in_addr mask4, *p4;
33022ce4affSfengbojiang 
33122ce4affSfengbojiang 	if (af == AF_INET) {
33222ce4affSfengbojiang 		p4 = (struct in_addr *)prefix;
33322ce4affSfengbojiang 		mask4.s_addr = htonl(~((1 << (32 - plen)) - 1));
33422ce4affSfengbojiang 		p4->s_addr &= mask4.s_addr;
33522ce4affSfengbojiang 	} else if (af == AF_INET6) {
33622ce4affSfengbojiang 		p6 = (struct in6_addr *)prefix;
33722ce4affSfengbojiang 		n2mask(&mask6, plen);
33822ce4affSfengbojiang 		APPLY_MASK(p6, &mask6);
33922ce4affSfengbojiang 	}
34022ce4affSfengbojiang }
34122ce4affSfengbojiang 
34222ce4affSfengbojiang static void
nat64lsn_parse_prefix(const char * arg,int af,void * prefix,uint16_t * plen)34322ce4affSfengbojiang nat64lsn_parse_prefix(const char *arg, int af, void *prefix, uint16_t *plen)
34422ce4affSfengbojiang {
34522ce4affSfengbojiang 	char *p, *l;
34622ce4affSfengbojiang 
34722ce4affSfengbojiang 	p = strdup(arg);
34822ce4affSfengbojiang 	if (p == NULL)
34922ce4affSfengbojiang 		err(EX_OSERR, NULL);
35022ce4affSfengbojiang 	if ((l = strchr(p, '/')) != NULL)
35122ce4affSfengbojiang 		*l++ = '\0';
35222ce4affSfengbojiang 	if (l == NULL)
35322ce4affSfengbojiang 		errx(EX_USAGE, "Prefix length required");
35422ce4affSfengbojiang 	if (inet_pton(af, p, prefix) != 1)
35522ce4affSfengbojiang 		errx(EX_USAGE, "Bad prefix: %s", p);
35622ce4affSfengbojiang 	*plen = (uint16_t)strtol(l, &l, 10);
35722ce4affSfengbojiang 	if (*l != '\0' || *plen == 0 || (af == AF_INET && *plen > 32) ||
35822ce4affSfengbojiang 	    (af == AF_INET6 && *plen > 96))
35922ce4affSfengbojiang 		errx(EX_USAGE, "Bad prefix length: %s", arg);
36022ce4affSfengbojiang 	nat64lsn_apply_mask(af, prefix, *plen);
36122ce4affSfengbojiang 	free(p);
36222ce4affSfengbojiang }
36322ce4affSfengbojiang 
36422ce4affSfengbojiang static uint32_t
nat64lsn_parse_int(const char * arg,const char * desc)36522ce4affSfengbojiang nat64lsn_parse_int(const char *arg, const char *desc)
36622ce4affSfengbojiang {
36722ce4affSfengbojiang 	char *p;
36822ce4affSfengbojiang 	uint32_t val;
36922ce4affSfengbojiang 
37022ce4affSfengbojiang 	val = (uint32_t)strtol(arg, &p, 10);
37122ce4affSfengbojiang 	if (*p != '\0')
37222ce4affSfengbojiang 		errx(EX_USAGE, "Invalid %s value: %s\n", desc, arg);
37322ce4affSfengbojiang 	return (val);
37422ce4affSfengbojiang }
37522ce4affSfengbojiang 
37622ce4affSfengbojiang static struct _s_x nat64newcmds[] = {
37722ce4affSfengbojiang       { "prefix6",	TOK_PREFIX6 },
37822ce4affSfengbojiang       { "jmaxlen",	TOK_JMAXLEN },
37922ce4affSfengbojiang       { "prefix4",	TOK_PREFIX4 },
38022ce4affSfengbojiang       { "host_del_age",	TOK_HOST_DEL_AGE },
38122ce4affSfengbojiang       { "pg_del_age",	TOK_PG_DEL_AGE },
38222ce4affSfengbojiang       { "tcp_syn_age",	TOK_TCP_SYN_AGE },
38322ce4affSfengbojiang       { "tcp_close_age",TOK_TCP_CLOSE_AGE },
38422ce4affSfengbojiang       { "tcp_est_age",	TOK_TCP_EST_AGE },
38522ce4affSfengbojiang       { "udp_age",	TOK_UDP_AGE },
38622ce4affSfengbojiang       { "icmp_age",	TOK_ICMP_AGE },
38722ce4affSfengbojiang       { "states_chunks",TOK_STATES_CHUNKS },
38822ce4affSfengbojiang       { "log",		TOK_LOG },
38922ce4affSfengbojiang       { "-log",		TOK_LOGOFF },
39022ce4affSfengbojiang       { "allow_private", TOK_PRIVATE },
39122ce4affSfengbojiang       { "-allow_private", TOK_PRIVATEOFF },
39222ce4affSfengbojiang       /* for compatibility with old configurations */
39322ce4affSfengbojiang       { "max_ports",	TOK_MAX_PORTS },	/* unused */
39422ce4affSfengbojiang       { NULL, 0 }
39522ce4affSfengbojiang };
39622ce4affSfengbojiang 
39722ce4affSfengbojiang /*
39822ce4affSfengbojiang  * Creates new nat64lsn instance
39922ce4affSfengbojiang  * ipfw nat64lsn <NAME> create
40022ce4affSfengbojiang  *     [ max_ports <N> ]
40122ce4affSfengbojiang  * Request: [ ipfw_obj_lheader ipfw_nat64lsn_cfg ]
40222ce4affSfengbojiang  */
40322ce4affSfengbojiang #define	NAT64LSN_HAS_PREFIX4	0x01
40422ce4affSfengbojiang #define	NAT64LSN_HAS_PREFIX6	0x02
40522ce4affSfengbojiang static void
nat64lsn_create(const char * name,uint8_t set,int ac,char ** av)40622ce4affSfengbojiang nat64lsn_create(const char *name, uint8_t set, int ac, char **av)
40722ce4affSfengbojiang {
40822ce4affSfengbojiang 	char buf[sizeof(ipfw_obj_lheader) + sizeof(ipfw_nat64lsn_cfg)];
40922ce4affSfengbojiang 	ipfw_nat64lsn_cfg *cfg;
41022ce4affSfengbojiang 	ipfw_obj_lheader *olh;
41122ce4affSfengbojiang 	int tcmd, flags;
41222ce4affSfengbojiang 	char *opt;
41322ce4affSfengbojiang 
41422ce4affSfengbojiang 	memset(&buf, 0, sizeof(buf));
41522ce4affSfengbojiang 	olh = (ipfw_obj_lheader *)buf;
41622ce4affSfengbojiang 	cfg = (ipfw_nat64lsn_cfg *)(olh + 1);
41722ce4affSfengbojiang 
41822ce4affSfengbojiang 	/* Some reasonable defaults */
41922ce4affSfengbojiang 	inet_pton(AF_INET6, "64:ff9b::", &cfg->prefix6);
42022ce4affSfengbojiang 	cfg->plen6 = 96;
42122ce4affSfengbojiang 	cfg->set = set;
42222ce4affSfengbojiang 	cfg->max_ports = NAT64LSN_MAX_PORTS;
42322ce4affSfengbojiang 	cfg->jmaxlen = NAT64LSN_JMAXLEN;
42422ce4affSfengbojiang 	cfg->nh_delete_delay = NAT64LSN_HOST_AGE;
42522ce4affSfengbojiang 	cfg->pg_delete_delay = NAT64LSN_PG_AGE;
42622ce4affSfengbojiang 	cfg->st_syn_ttl = NAT64LSN_TCP_SYN_AGE;
42722ce4affSfengbojiang 	cfg->st_estab_ttl = NAT64LSN_TCP_EST_AGE;
42822ce4affSfengbojiang 	cfg->st_close_ttl = NAT64LSN_TCP_FIN_AGE;
42922ce4affSfengbojiang 	cfg->st_udp_ttl = NAT64LSN_UDP_AGE;
43022ce4affSfengbojiang 	cfg->st_icmp_ttl = NAT64LSN_ICMP_AGE;
43122ce4affSfengbojiang 	flags = NAT64LSN_HAS_PREFIX6;
43222ce4affSfengbojiang 	while (ac > 0) {
43322ce4affSfengbojiang 		tcmd = get_token(nat64newcmds, *av, "option");
43422ce4affSfengbojiang 		opt = *av;
43522ce4affSfengbojiang 		ac--; av++;
43622ce4affSfengbojiang 
43722ce4affSfengbojiang 		switch (tcmd) {
43822ce4affSfengbojiang 		case TOK_PREFIX4:
43922ce4affSfengbojiang 			NEED1("IPv4 prefix required");
44022ce4affSfengbojiang 			nat64lsn_parse_prefix(*av, AF_INET, &cfg->prefix4,
44122ce4affSfengbojiang 			    &cfg->plen4);
44222ce4affSfengbojiang 			flags |= NAT64LSN_HAS_PREFIX4;
44322ce4affSfengbojiang 			ac--; av++;
44422ce4affSfengbojiang 			break;
44522ce4affSfengbojiang 		case TOK_PREFIX6:
44622ce4affSfengbojiang 			NEED1("IPv6 prefix required");
44722ce4affSfengbojiang 			nat64lsn_parse_prefix(*av, AF_INET6, &cfg->prefix6,
44822ce4affSfengbojiang 			    &cfg->plen6);
44922ce4affSfengbojiang 			if (ipfw_check_nat64prefix(&cfg->prefix6,
45022ce4affSfengbojiang 			    cfg->plen6) != 0 &&
45122ce4affSfengbojiang 			    !IN6_IS_ADDR_UNSPECIFIED(&cfg->prefix6))
45222ce4affSfengbojiang 				errx(EX_USAGE, "Bad prefix6 %s", *av);
45322ce4affSfengbojiang 
45422ce4affSfengbojiang 			ac--; av++;
45522ce4affSfengbojiang 			break;
45622ce4affSfengbojiang 		case TOK_JMAXLEN:
45722ce4affSfengbojiang 			NEED1("job queue length required");
45822ce4affSfengbojiang 			cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
45922ce4affSfengbojiang 			ac--; av++;
46022ce4affSfengbojiang 			break;
46122ce4affSfengbojiang 		case TOK_MAX_PORTS:
46222ce4affSfengbojiang 			NEED1("Max per-user ports required");
46322ce4affSfengbojiang 			cfg->max_ports = nat64lsn_parse_int(*av, opt);
46422ce4affSfengbojiang 			ac--; av++;
46522ce4affSfengbojiang 			break;
46622ce4affSfengbojiang 		case TOK_HOST_DEL_AGE:
46722ce4affSfengbojiang 			NEED1("host delete delay required");
46822ce4affSfengbojiang 			cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int(
46922ce4affSfengbojiang 			    *av, opt);
47022ce4affSfengbojiang 			ac--; av++;
47122ce4affSfengbojiang 			break;
47222ce4affSfengbojiang 		case TOK_PG_DEL_AGE:
47322ce4affSfengbojiang 			NEED1("portgroup delete delay required");
47422ce4affSfengbojiang 			cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int(
47522ce4affSfengbojiang 			    *av, opt);
47622ce4affSfengbojiang 			ac--; av++;
47722ce4affSfengbojiang 			break;
47822ce4affSfengbojiang 		case TOK_TCP_SYN_AGE:
47922ce4affSfengbojiang 			NEED1("tcp syn age required");
48022ce4affSfengbojiang 			cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int(
48122ce4affSfengbojiang 			    *av, opt);
48222ce4affSfengbojiang 			ac--; av++;
48322ce4affSfengbojiang 			break;
48422ce4affSfengbojiang 		case TOK_TCP_CLOSE_AGE:
48522ce4affSfengbojiang 			NEED1("tcp close age required");
48622ce4affSfengbojiang 			cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int(
48722ce4affSfengbojiang 			    *av, opt);
48822ce4affSfengbojiang 			ac--; av++;
48922ce4affSfengbojiang 			break;
49022ce4affSfengbojiang 		case TOK_TCP_EST_AGE:
49122ce4affSfengbojiang 			NEED1("tcp est age required");
49222ce4affSfengbojiang 			cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int(
49322ce4affSfengbojiang 			    *av, opt);
49422ce4affSfengbojiang 			ac--; av++;
49522ce4affSfengbojiang 			break;
49622ce4affSfengbojiang 		case TOK_UDP_AGE:
49722ce4affSfengbojiang 			NEED1("udp age required");
49822ce4affSfengbojiang 			cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int(
49922ce4affSfengbojiang 			    *av, opt);
50022ce4affSfengbojiang 			ac--; av++;
50122ce4affSfengbojiang 			break;
50222ce4affSfengbojiang 		case TOK_ICMP_AGE:
50322ce4affSfengbojiang 			NEED1("icmp age required");
50422ce4affSfengbojiang 			cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int(
50522ce4affSfengbojiang 			    *av, opt);
50622ce4affSfengbojiang 			ac--; av++;
50722ce4affSfengbojiang 			break;
50822ce4affSfengbojiang 		case TOK_STATES_CHUNKS:
50922ce4affSfengbojiang 			NEED1("number of chunks required");
51022ce4affSfengbojiang 			cfg->states_chunks = (uint8_t)nat64lsn_parse_int(
51122ce4affSfengbojiang 			    *av, opt);
51222ce4affSfengbojiang 			ac--; av++;
51322ce4affSfengbojiang 			break;
51422ce4affSfengbojiang 		case TOK_LOG:
51522ce4affSfengbojiang 			cfg->flags |= NAT64_LOG;
51622ce4affSfengbojiang 			break;
51722ce4affSfengbojiang 		case TOK_LOGOFF:
51822ce4affSfengbojiang 			cfg->flags &= ~NAT64_LOG;
51922ce4affSfengbojiang 			break;
52022ce4affSfengbojiang 		case TOK_PRIVATE:
52122ce4affSfengbojiang 			cfg->flags |= NAT64_ALLOW_PRIVATE;
52222ce4affSfengbojiang 			break;
52322ce4affSfengbojiang 		case TOK_PRIVATEOFF:
52422ce4affSfengbojiang 			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
52522ce4affSfengbojiang 			break;
52622ce4affSfengbojiang 		}
52722ce4affSfengbojiang 	}
52822ce4affSfengbojiang 
52922ce4affSfengbojiang 	/* Check validness */
53022ce4affSfengbojiang 	if ((flags & NAT64LSN_HAS_PREFIX4) != NAT64LSN_HAS_PREFIX4)
53122ce4affSfengbojiang 		errx(EX_USAGE, "prefix4 required");
53222ce4affSfengbojiang 
53322ce4affSfengbojiang 	olh->count = 1;
53422ce4affSfengbojiang 	olh->objsize = sizeof(*cfg);
53522ce4affSfengbojiang 	olh->size = sizeof(buf);
53622ce4affSfengbojiang 	strlcpy(cfg->name, name, sizeof(cfg->name));
53722ce4affSfengbojiang 	if (do_set3(IP_FW_NAT64LSN_CREATE, &olh->opheader, sizeof(buf)) != 0)
53822ce4affSfengbojiang 		err(EX_OSERR, "nat64lsn instance creation failed");
53922ce4affSfengbojiang }
54022ce4affSfengbojiang 
54122ce4affSfengbojiang /*
54222ce4affSfengbojiang  * Configures existing nat64lsn instance
54322ce4affSfengbojiang  * ipfw nat64lsn <NAME> config <options>
54422ce4affSfengbojiang  * Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ]
54522ce4affSfengbojiang  */
54622ce4affSfengbojiang static void
nat64lsn_config(const char * name,uint8_t set,int ac,char ** av)54722ce4affSfengbojiang nat64lsn_config(const char *name, uint8_t set, int ac, char **av)
54822ce4affSfengbojiang {
54922ce4affSfengbojiang 	char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64lsn_cfg)];
55022ce4affSfengbojiang 	ipfw_nat64lsn_cfg *cfg;
55122ce4affSfengbojiang 	ipfw_obj_header *oh;
55222ce4affSfengbojiang 	size_t sz;
55322ce4affSfengbojiang 	char *opt;
55422ce4affSfengbojiang 	int tcmd;
55522ce4affSfengbojiang 
55622ce4affSfengbojiang 	if (ac == 0)
55722ce4affSfengbojiang 		errx(EX_USAGE, "config options required");
55822ce4affSfengbojiang 	memset(&buf, 0, sizeof(buf));
55922ce4affSfengbojiang 	oh = (ipfw_obj_header *)buf;
56022ce4affSfengbojiang 	cfg = (ipfw_nat64lsn_cfg *)(oh + 1);
56122ce4affSfengbojiang 	sz = sizeof(buf);
56222ce4affSfengbojiang 
56322ce4affSfengbojiang 	nat64lsn_fill_ntlv(&oh->ntlv, name, set);
56422ce4affSfengbojiang 	if (do_get3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, &sz) != 0)
56522ce4affSfengbojiang 		err(EX_OSERR, "failed to get config for instance %s", name);
56622ce4affSfengbojiang 
56722ce4affSfengbojiang 	while (ac > 0) {
56822ce4affSfengbojiang 		tcmd = get_token(nat64newcmds, *av, "option");
56922ce4affSfengbojiang 		opt = *av;
57022ce4affSfengbojiang 		ac--; av++;
57122ce4affSfengbojiang 
57222ce4affSfengbojiang 		switch (tcmd) {
57322ce4affSfengbojiang 		case TOK_MAX_PORTS:
57422ce4affSfengbojiang 			NEED1("Max per-user ports required");
57522ce4affSfengbojiang 			cfg->max_ports = nat64lsn_parse_int(*av, opt);
57622ce4affSfengbojiang 			ac--; av++;
57722ce4affSfengbojiang 			break;
57822ce4affSfengbojiang 		case TOK_JMAXLEN:
57922ce4affSfengbojiang 			NEED1("job queue length required");
58022ce4affSfengbojiang 			cfg->jmaxlen = nat64lsn_parse_int(*av, opt);
58122ce4affSfengbojiang 			ac--; av++;
58222ce4affSfengbojiang 			break;
58322ce4affSfengbojiang 		case TOK_HOST_DEL_AGE:
58422ce4affSfengbojiang 			NEED1("host delete delay required");
58522ce4affSfengbojiang 			cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int(
58622ce4affSfengbojiang 			    *av, opt);
58722ce4affSfengbojiang 			ac--; av++;
58822ce4affSfengbojiang 			break;
58922ce4affSfengbojiang 		case TOK_PG_DEL_AGE:
59022ce4affSfengbojiang 			NEED1("portgroup delete delay required");
59122ce4affSfengbojiang 			cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int(
59222ce4affSfengbojiang 			    *av, opt);
59322ce4affSfengbojiang 			ac--; av++;
59422ce4affSfengbojiang 			break;
59522ce4affSfengbojiang 		case TOK_TCP_SYN_AGE:
59622ce4affSfengbojiang 			NEED1("tcp syn age required");
59722ce4affSfengbojiang 			cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int(
59822ce4affSfengbojiang 			    *av, opt);
59922ce4affSfengbojiang 			ac--; av++;
60022ce4affSfengbojiang 			break;
60122ce4affSfengbojiang 		case TOK_TCP_CLOSE_AGE:
60222ce4affSfengbojiang 			NEED1("tcp close age required");
60322ce4affSfengbojiang 			cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int(
60422ce4affSfengbojiang 			    *av, opt);
60522ce4affSfengbojiang 			ac--; av++;
60622ce4affSfengbojiang 			break;
60722ce4affSfengbojiang 		case TOK_TCP_EST_AGE:
60822ce4affSfengbojiang 			NEED1("tcp est age required");
60922ce4affSfengbojiang 			cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int(
61022ce4affSfengbojiang 			    *av, opt);
61122ce4affSfengbojiang 			ac--; av++;
61222ce4affSfengbojiang 			break;
61322ce4affSfengbojiang 		case TOK_UDP_AGE:
61422ce4affSfengbojiang 			NEED1("udp age required");
61522ce4affSfengbojiang 			cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int(
61622ce4affSfengbojiang 			    *av, opt);
61722ce4affSfengbojiang 			ac--; av++;
61822ce4affSfengbojiang 			break;
61922ce4affSfengbojiang 		case TOK_ICMP_AGE:
62022ce4affSfengbojiang 			NEED1("icmp age required");
62122ce4affSfengbojiang 			cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int(
62222ce4affSfengbojiang 			    *av, opt);
62322ce4affSfengbojiang 			ac--; av++;
62422ce4affSfengbojiang 			break;
62522ce4affSfengbojiang 		case TOK_STATES_CHUNKS:
62622ce4affSfengbojiang 			NEED1("number of chunks required");
62722ce4affSfengbojiang 			cfg->states_chunks = (uint8_t)nat64lsn_parse_int(
62822ce4affSfengbojiang 			    *av, opt);
62922ce4affSfengbojiang 			ac--; av++;
63022ce4affSfengbojiang 			break;
63122ce4affSfengbojiang 		case TOK_LOG:
63222ce4affSfengbojiang 			cfg->flags |= NAT64_LOG;
63322ce4affSfengbojiang 			break;
63422ce4affSfengbojiang 		case TOK_LOGOFF:
63522ce4affSfengbojiang 			cfg->flags &= ~NAT64_LOG;
63622ce4affSfengbojiang 			break;
63722ce4affSfengbojiang 		case TOK_PRIVATE:
63822ce4affSfengbojiang 			cfg->flags |= NAT64_ALLOW_PRIVATE;
63922ce4affSfengbojiang 			break;
64022ce4affSfengbojiang 		case TOK_PRIVATEOFF:
64122ce4affSfengbojiang 			cfg->flags &= ~NAT64_ALLOW_PRIVATE;
64222ce4affSfengbojiang 			break;
64322ce4affSfengbojiang 		default:
64422ce4affSfengbojiang 			errx(EX_USAGE, "Can't change %s option", opt);
64522ce4affSfengbojiang 		}
64622ce4affSfengbojiang 	}
64722ce4affSfengbojiang 
64822ce4affSfengbojiang 	if (do_set3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, sizeof(buf)) != 0)
64922ce4affSfengbojiang 		err(EX_OSERR, "nat64lsn instance configuration failed");
65022ce4affSfengbojiang }
65122ce4affSfengbojiang 
65222ce4affSfengbojiang /*
65322ce4affSfengbojiang  * Reset nat64lsn instance statistics specified by @oh->ntlv.
65422ce4affSfengbojiang  * Request: [ ipfw_obj_header ]
65522ce4affSfengbojiang  */
65622ce4affSfengbojiang static void
nat64lsn_reset_stats(const char * name,uint8_t set)65722ce4affSfengbojiang nat64lsn_reset_stats(const char *name, uint8_t set)
65822ce4affSfengbojiang {
65922ce4affSfengbojiang 	ipfw_obj_header oh;
66022ce4affSfengbojiang 
66122ce4affSfengbojiang 	memset(&oh, 0, sizeof(oh));
66222ce4affSfengbojiang 	nat64lsn_fill_ntlv(&oh.ntlv, name, set);
66322ce4affSfengbojiang 	if (do_set3(IP_FW_NAT64LSN_RESET_STATS, &oh.opheader, sizeof(oh)) != 0)
66422ce4affSfengbojiang 		err(EX_OSERR, "failed to reset stats for instance %s", name);
66522ce4affSfengbojiang }
66622ce4affSfengbojiang 
66722ce4affSfengbojiang /*
66822ce4affSfengbojiang  * Destroys nat64lsn instance specified by @oh->ntlv.
66922ce4affSfengbojiang  * Request: [ ipfw_obj_header ]
67022ce4affSfengbojiang  */
67122ce4affSfengbojiang static void
nat64lsn_destroy(const char * name,uint8_t set)67222ce4affSfengbojiang nat64lsn_destroy(const char *name, uint8_t set)
67322ce4affSfengbojiang {
67422ce4affSfengbojiang 	ipfw_obj_header oh;
67522ce4affSfengbojiang 
67622ce4affSfengbojiang 	memset(&oh, 0, sizeof(oh));
67722ce4affSfengbojiang 	nat64lsn_fill_ntlv(&oh.ntlv, name, set);
67822ce4affSfengbojiang 	if (do_set3(IP_FW_NAT64LSN_DESTROY, &oh.opheader, sizeof(oh)) != 0)
67922ce4affSfengbojiang 		err(EX_OSERR, "failed to destroy nat instance %s", name);
68022ce4affSfengbojiang }
68122ce4affSfengbojiang 
68222ce4affSfengbojiang /*
68322ce4affSfengbojiang  * Get nat64lsn instance statistics.
68422ce4affSfengbojiang  * Request: [ ipfw_obj_header ]
68522ce4affSfengbojiang  * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ]
68622ce4affSfengbojiang  */
68722ce4affSfengbojiang static int
nat64lsn_get_stats(const char * name,uint8_t set,struct ipfw_nat64lsn_stats * stats)68822ce4affSfengbojiang nat64lsn_get_stats(const char *name, uint8_t set,
68922ce4affSfengbojiang     struct ipfw_nat64lsn_stats *stats)
69022ce4affSfengbojiang {
69122ce4affSfengbojiang 	ipfw_obj_header *oh;
69222ce4affSfengbojiang 	ipfw_obj_ctlv *oc;
69322ce4affSfengbojiang 	size_t sz;
69422ce4affSfengbojiang 
69522ce4affSfengbojiang 	sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats);
69622ce4affSfengbojiang 	oh = calloc(1, sz);
69722ce4affSfengbojiang 	nat64lsn_fill_ntlv(&oh->ntlv, name, set);
69822ce4affSfengbojiang 	if (do_get3(IP_FW_NAT64LSN_STATS, &oh->opheader, &sz) == 0) {
69922ce4affSfengbojiang 		oc = (ipfw_obj_ctlv *)(oh + 1);
70022ce4affSfengbojiang 		memcpy(stats, oc + 1, sizeof(*stats));
70122ce4affSfengbojiang 		free(oh);
70222ce4affSfengbojiang 		return (0);
70322ce4affSfengbojiang 	}
70422ce4affSfengbojiang 	free(oh);
70522ce4affSfengbojiang 	return (-1);
70622ce4affSfengbojiang }
70722ce4affSfengbojiang 
70822ce4affSfengbojiang static void
nat64lsn_stats(const char * name,uint8_t set)70922ce4affSfengbojiang nat64lsn_stats(const char *name, uint8_t set)
71022ce4affSfengbojiang {
71122ce4affSfengbojiang 	struct ipfw_nat64lsn_stats stats;
71222ce4affSfengbojiang 
71322ce4affSfengbojiang 	if (nat64lsn_get_stats(name, set, &stats) != 0)
71422ce4affSfengbojiang 		err(EX_OSERR, "Error retrieving stats");
71522ce4affSfengbojiang 
71622ce4affSfengbojiang 	if (g_co.use_set != 0 || set != 0)
71722ce4affSfengbojiang 		printf("set %u ", set);
71822ce4affSfengbojiang 	printf("nat64lsn %s\n", name);
71922ce4affSfengbojiang 	printf("\t%ju packets translated from IPv6 to IPv4\n",
72022ce4affSfengbojiang 	    (uintmax_t)stats.opcnt64);
72122ce4affSfengbojiang 	printf("\t%ju packets translated from IPv4 to IPv6\n",
72222ce4affSfengbojiang 	    (uintmax_t)stats.opcnt46);
72322ce4affSfengbojiang 	printf("\t%ju IPv6 fragments created\n",
72422ce4affSfengbojiang 	    (uintmax_t)stats.ofrags);
72522ce4affSfengbojiang 	printf("\t%ju IPv4 fragments received\n",
72622ce4affSfengbojiang 	    (uintmax_t)stats.ifrags);
72722ce4affSfengbojiang 	printf("\t%ju output packets dropped due to no bufs, etc.\n",
72822ce4affSfengbojiang 	    (uintmax_t)stats.oerrors);
72922ce4affSfengbojiang 	printf("\t%ju output packets discarded due to no IPv4 route\n",
73022ce4affSfengbojiang 	    (uintmax_t)stats.noroute4);
73122ce4affSfengbojiang 	printf("\t%ju output packets discarded due to no IPv6 route\n",
73222ce4affSfengbojiang 	    (uintmax_t)stats.noroute6);
73322ce4affSfengbojiang 	printf("\t%ju packets discarded due to unsupported protocol\n",
73422ce4affSfengbojiang 	    (uintmax_t)stats.noproto);
73522ce4affSfengbojiang 	printf("\t%ju packets discarded due to memory allocation problems\n",
73622ce4affSfengbojiang 	    (uintmax_t)stats.nomem);
73722ce4affSfengbojiang 	printf("\t%ju packets discarded due to some errors\n",
73822ce4affSfengbojiang 	    (uintmax_t)stats.dropped);
73922ce4affSfengbojiang 	printf("\t%ju packets not matched with IPv4 prefix\n",
74022ce4affSfengbojiang 	    (uintmax_t)stats.nomatch4);
74122ce4affSfengbojiang 
74222ce4affSfengbojiang 	printf("\t%ju mbufs queued for post processing\n",
74322ce4affSfengbojiang 	    (uintmax_t)stats.jreinjected);
74422ce4affSfengbojiang 	printf("\t%ju times the job queue was processed\n",
74522ce4affSfengbojiang 	    (uintmax_t)stats.jcalls);
74622ce4affSfengbojiang 	printf("\t%ju job requests queued\n",
74722ce4affSfengbojiang 	    (uintmax_t)stats.jrequests);
74822ce4affSfengbojiang 	printf("\t%ju job requests queue limit reached\n",
74922ce4affSfengbojiang 	    (uintmax_t)stats.jmaxlen);
75022ce4affSfengbojiang 	printf("\t%ju job requests failed due to memory allocation problems\n",
75122ce4affSfengbojiang 	    (uintmax_t)stats.jnomem);
75222ce4affSfengbojiang 
75322ce4affSfengbojiang 	printf("\t%ju hosts allocated\n", (uintmax_t)stats.hostcount);
75422ce4affSfengbojiang 	printf("\t%ju hosts requested\n", (uintmax_t)stats.jhostsreq);
75522ce4affSfengbojiang 	printf("\t%ju host requests failed\n", (uintmax_t)stats.jhostfails);
75622ce4affSfengbojiang 
75722ce4affSfengbojiang 	printf("\t%ju portgroups requested\n", (uintmax_t)stats.jportreq);
75822ce4affSfengbojiang 	printf("\t%ju portgroups allocated\n", (uintmax_t)stats.spgcreated);
75922ce4affSfengbojiang 	printf("\t%ju portgroups deleted\n", (uintmax_t)stats.spgdeleted);
76022ce4affSfengbojiang 	printf("\t%ju portgroup requests failed\n",
76122ce4affSfengbojiang 	    (uintmax_t)stats.jportfails);
76222ce4affSfengbojiang 	printf("\t%ju portgroups allocated for TCP\n",
76322ce4affSfengbojiang 	    (uintmax_t)stats.tcpchunks);
76422ce4affSfengbojiang 	printf("\t%ju portgroups allocated for UDP\n",
76522ce4affSfengbojiang 	    (uintmax_t)stats.udpchunks);
76622ce4affSfengbojiang 	printf("\t%ju portgroups allocated for ICMP\n",
76722ce4affSfengbojiang 	    (uintmax_t)stats.icmpchunks);
76822ce4affSfengbojiang 
76922ce4affSfengbojiang 	printf("\t%ju states created\n", (uintmax_t)stats.screated);
77022ce4affSfengbojiang 	printf("\t%ju states deleted\n", (uintmax_t)stats.sdeleted);
77122ce4affSfengbojiang }
77222ce4affSfengbojiang 
77322ce4affSfengbojiang static int
nat64lsn_show_cb(ipfw_nat64lsn_cfg * cfg,const char * name,uint8_t set)77422ce4affSfengbojiang nat64lsn_show_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set)
77522ce4affSfengbojiang {
77622ce4affSfengbojiang 	char abuf[INET6_ADDRSTRLEN];
77722ce4affSfengbojiang 
77822ce4affSfengbojiang 	if (name != NULL && strcmp(cfg->name, name) != 0)
77922ce4affSfengbojiang 		return (ESRCH);
78022ce4affSfengbojiang 
78122ce4affSfengbojiang 	if (g_co.use_set != 0 && cfg->set != set)
78222ce4affSfengbojiang 		return (ESRCH);
78322ce4affSfengbojiang 
78422ce4affSfengbojiang 	if (g_co.use_set != 0 || cfg->set != 0)
78522ce4affSfengbojiang 		printf("set %u ", cfg->set);
78622ce4affSfengbojiang 	inet_ntop(AF_INET, &cfg->prefix4, abuf, sizeof(abuf));
78722ce4affSfengbojiang 	printf("nat64lsn %s prefix4 %s/%u", cfg->name, abuf, cfg->plen4);
78822ce4affSfengbojiang 	inet_ntop(AF_INET6, &cfg->prefix6, abuf, sizeof(abuf));
78922ce4affSfengbojiang 	printf(" prefix6 %s/%u", abuf, cfg->plen6);
79022ce4affSfengbojiang 	if (g_co.verbose || cfg->states_chunks > 1)
79122ce4affSfengbojiang 		printf(" states_chunks %u", cfg->states_chunks);
79222ce4affSfengbojiang 	if (g_co.verbose || cfg->nh_delete_delay != NAT64LSN_HOST_AGE)
79322ce4affSfengbojiang 		printf(" host_del_age %u", cfg->nh_delete_delay);
79422ce4affSfengbojiang 	if (g_co.verbose || cfg->pg_delete_delay != NAT64LSN_PG_AGE)
79522ce4affSfengbojiang 		printf(" pg_del_age %u", cfg->pg_delete_delay);
79622ce4affSfengbojiang 	if (g_co.verbose || cfg->st_syn_ttl != NAT64LSN_TCP_SYN_AGE)
79722ce4affSfengbojiang 		printf(" tcp_syn_age %u", cfg->st_syn_ttl);
79822ce4affSfengbojiang 	if (g_co.verbose || cfg->st_close_ttl != NAT64LSN_TCP_FIN_AGE)
79922ce4affSfengbojiang 		printf(" tcp_close_age %u", cfg->st_close_ttl);
80022ce4affSfengbojiang 	if (g_co.verbose || cfg->st_estab_ttl != NAT64LSN_TCP_EST_AGE)
80122ce4affSfengbojiang 		printf(" tcp_est_age %u", cfg->st_estab_ttl);
80222ce4affSfengbojiang 	if (g_co.verbose || cfg->st_udp_ttl != NAT64LSN_UDP_AGE)
80322ce4affSfengbojiang 		printf(" udp_age %u", cfg->st_udp_ttl);
80422ce4affSfengbojiang 	if (g_co.verbose || cfg->st_icmp_ttl != NAT64LSN_ICMP_AGE)
80522ce4affSfengbojiang 		printf(" icmp_age %u", cfg->st_icmp_ttl);
80622ce4affSfengbojiang 	if (g_co.verbose || cfg->jmaxlen != NAT64LSN_JMAXLEN)
80722ce4affSfengbojiang 		printf(" jmaxlen %u", cfg->jmaxlen);
80822ce4affSfengbojiang 	if (cfg->flags & NAT64_LOG)
80922ce4affSfengbojiang 		printf(" log");
81022ce4affSfengbojiang 	if (cfg->flags & NAT64_ALLOW_PRIVATE)
81122ce4affSfengbojiang 		printf(" allow_private");
81222ce4affSfengbojiang 	printf("\n");
81322ce4affSfengbojiang 	return (0);
81422ce4affSfengbojiang }
81522ce4affSfengbojiang 
81622ce4affSfengbojiang static int
nat64lsn_destroy_cb(ipfw_nat64lsn_cfg * cfg,const char * name __unused,uint8_t set)81722ce4affSfengbojiang nat64lsn_destroy_cb(ipfw_nat64lsn_cfg *cfg, const char *name __unused,
81822ce4affSfengbojiang     uint8_t set)
81922ce4affSfengbojiang {
82022ce4affSfengbojiang 
82122ce4affSfengbojiang 	if (g_co.use_set != 0 && cfg->set != set)
82222ce4affSfengbojiang 		return (ESRCH);
82322ce4affSfengbojiang 
82422ce4affSfengbojiang 	nat64lsn_destroy(cfg->name, cfg->set);
82522ce4affSfengbojiang 	return (0);
82622ce4affSfengbojiang }
82722ce4affSfengbojiang 
82822ce4affSfengbojiang 
82922ce4affSfengbojiang /*
83022ce4affSfengbojiang  * Compare nat64lsn instances names.
83122ce4affSfengbojiang  * Honor number comparison.
83222ce4affSfengbojiang  */
83322ce4affSfengbojiang static int
nat64name_cmp(const void * a,const void * b)83422ce4affSfengbojiang nat64name_cmp(const void *a, const void *b)
83522ce4affSfengbojiang {
83622ce4affSfengbojiang 	const ipfw_nat64lsn_cfg *ca, *cb;
83722ce4affSfengbojiang 
83822ce4affSfengbojiang 	ca = (const ipfw_nat64lsn_cfg *)a;
83922ce4affSfengbojiang 	cb = (const ipfw_nat64lsn_cfg *)b;
84022ce4affSfengbojiang 
84122ce4affSfengbojiang 	if (ca->set > cb->set)
84222ce4affSfengbojiang 		return (1);
84322ce4affSfengbojiang 	else if (ca->set < cb->set)
84422ce4affSfengbojiang 		return (-1);
84522ce4affSfengbojiang 	return (stringnum_cmp(ca->name, cb->name));
84622ce4affSfengbojiang }
84722ce4affSfengbojiang 
84822ce4affSfengbojiang /*
84922ce4affSfengbojiang  * Retrieves nat64lsn instance list from kernel,
85022ce4affSfengbojiang  * optionally sorts it and calls requested function for each instance.
85122ce4affSfengbojiang  *
85222ce4affSfengbojiang  * Request: [ ipfw_obj_lheader ]
85322ce4affSfengbojiang  * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ]
85422ce4affSfengbojiang  */
85522ce4affSfengbojiang static int
nat64lsn_foreach(nat64lsn_cb_t * f,const char * name,uint8_t set,int sort)85622ce4affSfengbojiang nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set,  int sort)
85722ce4affSfengbojiang {
85822ce4affSfengbojiang 	ipfw_obj_lheader *olh;
85922ce4affSfengbojiang 	ipfw_nat64lsn_cfg *cfg;
86022ce4affSfengbojiang 	size_t sz;
86122ce4affSfengbojiang 	uint32_t i;
86222ce4affSfengbojiang 	int error;
86322ce4affSfengbojiang 
86422ce4affSfengbojiang 	/* Start with reasonable default */
86522ce4affSfengbojiang 	sz = sizeof(*olh) + 16 * sizeof(ipfw_nat64lsn_cfg);
86622ce4affSfengbojiang 
86722ce4affSfengbojiang 	for (;;) {
86822ce4affSfengbojiang 		if ((olh = calloc(1, sz)) == NULL)
86922ce4affSfengbojiang 			return (ENOMEM);
87022ce4affSfengbojiang 
87122ce4affSfengbojiang 		olh->size = sz;
87222ce4affSfengbojiang 		if (do_get3(IP_FW_NAT64LSN_LIST, &olh->opheader, &sz) != 0) {
87322ce4affSfengbojiang 			sz = olh->size;
87422ce4affSfengbojiang 			free(olh);
87522ce4affSfengbojiang 			if (errno != ENOMEM)
87622ce4affSfengbojiang 				return (errno);
87722ce4affSfengbojiang 			continue;
87822ce4affSfengbojiang 		}
87922ce4affSfengbojiang 
88022ce4affSfengbojiang 		if (sort != 0)
88122ce4affSfengbojiang 			qsort(olh + 1, olh->count, olh->objsize,
88222ce4affSfengbojiang 			    nat64name_cmp);
88322ce4affSfengbojiang 
88422ce4affSfengbojiang 		cfg = (ipfw_nat64lsn_cfg *)(olh + 1);
88522ce4affSfengbojiang 		for (i = 0; i < olh->count; i++) {
88622ce4affSfengbojiang 			error = f(cfg, name, set); /* Ignore errors for now */
88722ce4affSfengbojiang 			cfg = (ipfw_nat64lsn_cfg *)((caddr_t)cfg +
88822ce4affSfengbojiang 			    olh->objsize);
88922ce4affSfengbojiang 		}
89022ce4affSfengbojiang 		free(olh);
89122ce4affSfengbojiang 		break;
89222ce4affSfengbojiang 	}
89322ce4affSfengbojiang 	return (0);
89422ce4affSfengbojiang }
89522ce4affSfengbojiang 
896