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