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