Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ipfw/nat.c
39475 views
1
/*-
2
* Copyright (c) 2002-2003 Luigi Rizzo
3
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4
* Copyright (c) 1994 Ugen J.S.Antsilevich
5
*
6
* Idea and grammar partially left from:
7
* Copyright (c) 1993 Daniel Boulet
8
*
9
* Redistribution and use in source forms, with and without modification,
10
* are permitted provided that this entire comment appears intact.
11
*
12
* Redistribution in binary form may occur without any restrictions.
13
* Obviously, it would be nice if you gave credit where credit is due
14
* but requiring it would be too onerous.
15
*
16
* This software is provided ``AS IS'' without any warranties of any kind.
17
*
18
* NEW command line interface for IP firewall facility
19
*
20
* In-kernel nat support
21
*/
22
23
#include <sys/types.h>
24
#include <sys/socket.h>
25
#include <sys/sysctl.h>
26
27
#include "ipfw2.h"
28
29
#include <ctype.h>
30
#include <err.h>
31
#include <errno.h>
32
#include <netdb.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <sysexits.h>
37
38
#include <net/if.h>
39
#include <net/if_dl.h>
40
#include <net/route.h> /* def. of struct route */
41
#include <netinet/in.h>
42
#include <netinet/ip_fw.h>
43
#include <arpa/inet.h>
44
#include <alias.h>
45
46
typedef int (nat_cb_t)(struct nat44_cfg_nat *cfg, void *arg);
47
static void nat_show_cfg(struct nat44_cfg_nat *n, void *arg);
48
static void nat_show_log(struct nat44_cfg_nat *n, void *arg);
49
static int nat_show_data(struct nat44_cfg_nat *cfg, void *arg);
50
static int natname_cmp(const void *a, const void *b);
51
static int nat_foreach(nat_cb_t *f, void *arg, int sort);
52
static int nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh);
53
54
static struct _s_x nat_params[] = {
55
{ "ip", TOK_IP },
56
{ "if", TOK_IF },
57
{ "log", TOK_ALOG },
58
{ "deny_in", TOK_DENY_INC },
59
{ "same_ports", TOK_SAME_PORTS },
60
{ "unreg_only", TOK_UNREG_ONLY },
61
{ "unreg_cgn", TOK_UNREG_CGN },
62
{ "skip_global", TOK_SKIP_GLOBAL },
63
{ "reset", TOK_RESET_ADDR },
64
{ "reverse", TOK_ALIAS_REV },
65
{ "proxy_only", TOK_PROXY_ONLY },
66
{ "port_range", TOK_PORT_ALIAS },
67
{ "redirect_addr", TOK_REDIR_ADDR },
68
{ "redirect_port", TOK_REDIR_PORT },
69
{ "redirect_proto", TOK_REDIR_PROTO },
70
{ "udp_eim", TOK_UDP_EIM },
71
{ NULL, 0 } /* terminator */
72
};
73
74
75
/*
76
* Search for interface with name "ifn", and fill n accordingly:
77
*
78
* n->ip ip address of interface "ifn"
79
* n->if_name copy of interface name "ifn"
80
*/
81
static void
82
set_addr_dynamic(const char *ifn, struct nat44_cfg_nat *n)
83
{
84
size_t needed;
85
int mib[6];
86
char *buf, *lim, *next;
87
struct if_msghdr *ifm;
88
struct ifa_msghdr *ifam;
89
struct sockaddr_dl *sdl;
90
struct sockaddr_in *sin;
91
int ifIndex;
92
93
mib[0] = CTL_NET;
94
mib[1] = PF_ROUTE;
95
mib[2] = 0;
96
mib[3] = AF_INET;
97
mib[4] = NET_RT_IFLIST;
98
mib[5] = 0;
99
/*
100
* Get interface data.
101
*/
102
if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
103
err(1, "iflist-sysctl-estimate");
104
buf = safe_calloc(1, needed);
105
if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
106
err(1, "iflist-sysctl-get");
107
lim = buf + needed;
108
/*
109
* Loop through interfaces until one with
110
* given name is found. This is done to
111
* find correct interface index for routing
112
* message processing.
113
*/
114
ifIndex = 0;
115
next = buf;
116
while (next < lim) {
117
ifm = (struct if_msghdr *)next;
118
next += ifm->ifm_msglen;
119
if (ifm->ifm_version != RTM_VERSION) {
120
if (g_co.verbose)
121
warnx("routing message version %d "
122
"not understood", ifm->ifm_version);
123
continue;
124
}
125
if (ifm->ifm_type == RTM_IFINFO) {
126
sdl = (struct sockaddr_dl *)(ifm + 1);
127
if (strlen(ifn) == sdl->sdl_nlen &&
128
strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
129
ifIndex = ifm->ifm_index;
130
break;
131
}
132
}
133
}
134
if (!ifIndex)
135
errx(1, "unknown interface name %s", ifn);
136
/*
137
* Get interface address.
138
*/
139
sin = NULL;
140
while (next < lim) {
141
ifam = (struct ifa_msghdr *)next;
142
next += ifam->ifam_msglen;
143
if (ifam->ifam_version != RTM_VERSION) {
144
if (g_co.verbose)
145
warnx("routing message version %d "
146
"not understood", ifam->ifam_version);
147
continue;
148
}
149
if (ifam->ifam_type != RTM_NEWADDR)
150
break;
151
if (ifam->ifam_addrs & RTA_IFA) {
152
int i;
153
char *cp = (char *)(ifam + 1);
154
155
for (i = 1; i < RTA_IFA; i <<= 1) {
156
if (ifam->ifam_addrs & i)
157
cp += SA_SIZE((struct sockaddr *)cp);
158
}
159
if (((struct sockaddr *)cp)->sa_family == AF_INET) {
160
sin = (struct sockaddr_in *)cp;
161
break;
162
}
163
}
164
}
165
if (sin == NULL)
166
n->ip.s_addr = htonl(INADDR_ANY);
167
else
168
n->ip = sin->sin_addr;
169
strncpy(n->if_name, ifn, IF_NAMESIZE);
170
171
free(buf);
172
}
173
174
/*
175
* XXX - The following functions, macros and definitions come from natd.c:
176
* it would be better to move them outside natd.c, in a file
177
* (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live
178
* with it.
179
*/
180
181
/*
182
* Definition of a port range, and macros to deal with values.
183
* FORMAT: HI 16-bits == first port in range, 0 == all ports.
184
* LO 16-bits == number of ports in range
185
* NOTES: - Port values are not stored in network byte order.
186
*/
187
188
#define port_range u_long
189
190
#define GETLOPORT(x) ((x) >> 0x10)
191
#define GETNUMPORTS(x) ((x) & 0x0000ffff)
192
#define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
193
194
/* Set y to be the low-port value in port_range variable x. */
195
#define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
196
197
/* Set y to be the number of ports in port_range variable x. */
198
#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
199
200
static void
201
StrToAddr (const char* str, struct in_addr* addr)
202
{
203
struct hostent* hp;
204
205
if (inet_aton (str, addr))
206
return;
207
208
hp = gethostbyname (str);
209
if (!hp)
210
errx (1, "unknown host %s", str);
211
212
memcpy (addr, hp->h_addr, sizeof (struct in_addr));
213
}
214
215
static int
216
StrToPortRange (const char* str, const char* proto, port_range *portRange)
217
{
218
char* sep;
219
struct servent* sp;
220
char* end;
221
u_short loPort;
222
u_short hiPort;
223
224
/* First see if this is a service, return corresponding port if so. */
225
sp = getservbyname (str,proto);
226
if (sp) {
227
SETLOPORT(*portRange, ntohs(sp->s_port));
228
SETNUMPORTS(*portRange, 1);
229
return 0;
230
}
231
232
/* Not a service, see if it's a single port or port range. */
233
sep = strchr (str, '-');
234
if (sep == NULL) {
235
SETLOPORT(*portRange, strtol(str, &end, 10));
236
if (end != str) {
237
/* Single port. */
238
SETNUMPORTS(*portRange, 1);
239
return 0;
240
}
241
242
/* Error in port range field. */
243
errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
244
}
245
246
/* Port range, get the values and sanity check. */
247
sscanf (str, "%hu-%hu", &loPort, &hiPort);
248
SETLOPORT(*portRange, loPort);
249
SETNUMPORTS(*portRange, 0); /* Error by default */
250
if (loPort <= hiPort)
251
SETNUMPORTS(*portRange, hiPort - loPort + 1);
252
253
if (GETNUMPORTS(*portRange) == 0)
254
errx (EX_DATAERR, "invalid port range %s", str);
255
256
return 0;
257
}
258
259
static int
260
StrToProto (const char* str)
261
{
262
if (!strcmp (str, "tcp"))
263
return IPPROTO_TCP;
264
265
if (!strcmp (str, "udp"))
266
return IPPROTO_UDP;
267
268
if (!strcmp (str, "sctp"))
269
return IPPROTO_SCTP;
270
errx (EX_DATAERR, "unknown protocol %s. Expected sctp, tcp or udp", str);
271
}
272
273
static int
274
StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto,
275
port_range *portRange)
276
{
277
char* ptr;
278
279
ptr = strchr (str, ':');
280
if (!ptr)
281
errx (EX_DATAERR, "%s is missing port number", str);
282
283
*ptr = '\0';
284
++ptr;
285
286
StrToAddr (str, addr);
287
return StrToPortRange (ptr, proto, portRange);
288
}
289
290
/* End of stuff taken from natd.c. */
291
292
/*
293
* The next 3 functions add support for the addr, port and proto redirect and
294
* their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect()
295
* and SetupProtoRedirect() from natd.c.
296
*
297
* Every setup_* function fills at least one redirect entry
298
* (struct nat44_cfg_redir) and zero or more server pool entry
299
* (struct nat44_cfg_spool) in buf.
300
*
301
* The format of data in buf is:
302
*
303
* nat44_cfg_nat nat44_cfg_redir nat44_cfg_spool ...... nat44_cfg_spool
304
*
305
* ------------------------------------- ------------
306
* | | .....X ..... | | | | .....
307
* ------------------------------------- ...... ------------
308
* ^
309
* spool_cnt n=0 ...... n=(X-1)
310
*
311
* len points to the amount of available space in buf
312
* space counts the memory consumed by every function
313
*
314
* XXX - Every function get all the argv params so it
315
* has to check, in optional parameters, that the next
316
* args is a valid option for the redir entry and not
317
* another token. Only redir_port and redir_proto are
318
* affected by this.
319
*/
320
321
static int
322
estimate_redir_addr(int *ac, char ***av)
323
{
324
size_t space = sizeof(struct nat44_cfg_redir);
325
char *sep = **av;
326
u_int c = 0;
327
328
(void)ac; /* UNUSED */
329
while ((sep = strchr(sep, ',')) != NULL) {
330
c++;
331
sep++;
332
}
333
334
if (c > 0)
335
c++;
336
337
space += c * sizeof(struct nat44_cfg_spool);
338
339
return (space);
340
}
341
342
static int
343
setup_redir_addr(char *buf, int *ac, char ***av)
344
{
345
struct nat44_cfg_redir *r;
346
char *sep;
347
size_t space;
348
349
r = (struct nat44_cfg_redir *)buf;
350
r->mode = REDIR_ADDR;
351
/* Skip nat44_cfg_redir at beginning of buf. */
352
buf = &buf[sizeof(struct nat44_cfg_redir)];
353
space = sizeof(struct nat44_cfg_redir);
354
355
/* Extract local address. */
356
if (strchr(**av, ',') != NULL) {
357
struct nat44_cfg_spool *spool;
358
359
/* Setup LSNAT server pool. */
360
r->laddr.s_addr = INADDR_NONE;
361
sep = strtok(**av, ",");
362
while (sep != NULL) {
363
spool = (struct nat44_cfg_spool *)buf;
364
space += sizeof(struct nat44_cfg_spool);
365
StrToAddr(sep, &spool->addr);
366
spool->port = ~0;
367
r->spool_cnt++;
368
/* Point to the next possible nat44_cfg_spool. */
369
buf = &buf[sizeof(struct nat44_cfg_spool)];
370
sep = strtok(NULL, ",");
371
}
372
} else
373
StrToAddr(**av, &r->laddr);
374
(*av)++; (*ac)--;
375
376
/* Extract public address. */
377
StrToAddr(**av, &r->paddr);
378
(*av)++; (*ac)--;
379
380
return (space);
381
}
382
383
static int
384
estimate_redir_port(int *ac, char ***av)
385
{
386
size_t space = sizeof(struct nat44_cfg_redir);
387
char *sep = **av;
388
u_int c = 0;
389
390
(void)ac; /* UNUSED */
391
while ((sep = strchr(sep, ',')) != NULL) {
392
c++;
393
sep++;
394
}
395
396
if (c > 0)
397
c++;
398
399
space += c * sizeof(struct nat44_cfg_spool);
400
401
return (space);
402
}
403
404
static int
405
setup_redir_port(char *buf, int *ac, char ***av)
406
{
407
struct nat44_cfg_redir *r;
408
char *sep, *protoName, *lsnat = NULL;
409
size_t space;
410
u_short numLocalPorts;
411
port_range portRange;
412
413
numLocalPorts = 0;
414
415
r = (struct nat44_cfg_redir *)buf;
416
r->mode = REDIR_PORT;
417
/* Skip nat44_cfg_redir at beginning of buf. */
418
buf = &buf[sizeof(struct nat44_cfg_redir)];
419
space = sizeof(struct nat44_cfg_redir);
420
421
/*
422
* Extract protocol.
423
*/
424
r->proto = StrToProto(**av);
425
protoName = **av;
426
(*av)++; (*ac)--;
427
428
/*
429
* Extract local address.
430
*/
431
if (strchr(**av, ',') != NULL) {
432
r->laddr.s_addr = INADDR_NONE;
433
r->lport = ~0;
434
numLocalPorts = 1;
435
lsnat = **av;
436
} else {
437
/*
438
* The sctp nat does not allow the port numbers to be mapped to
439
* new port numbers. Therefore, no ports are to be specified
440
* in the target port field.
441
*/
442
if (r->proto == IPPROTO_SCTP) {
443
if (strchr(**av, ':'))
444
errx(EX_DATAERR, "redirect_port:"
445
"port numbers do not change in sctp, so do "
446
"not specify them as part of the target");
447
else
448
StrToAddr(**av, &r->laddr);
449
} else {
450
if (StrToAddrAndPortRange(**av, &r->laddr, protoName,
451
&portRange) != 0)
452
errx(EX_DATAERR, "redirect_port: "
453
"invalid local port range");
454
455
r->lport = GETLOPORT(portRange);
456
numLocalPorts = GETNUMPORTS(portRange);
457
}
458
}
459
(*av)++; (*ac)--;
460
461
/*
462
* Extract public port and optionally address.
463
*/
464
if (strchr(**av, ':') != NULL) {
465
if (StrToAddrAndPortRange(**av, &r->paddr, protoName,
466
&portRange) != 0)
467
errx(EX_DATAERR, "redirect_port: "
468
"invalid public port range");
469
} else {
470
r->paddr.s_addr = INADDR_ANY;
471
if (StrToPortRange(**av, protoName, &portRange) != 0)
472
errx(EX_DATAERR, "redirect_port: "
473
"invalid public port range");
474
}
475
476
r->pport = GETLOPORT(portRange);
477
if (r->proto == IPPROTO_SCTP) { /* so the logic below still works */
478
numLocalPorts = GETNUMPORTS(portRange);
479
r->lport = r->pport;
480
}
481
r->pport_cnt = GETNUMPORTS(portRange);
482
(*av)++; (*ac)--;
483
484
/*
485
* Extract remote address and optionally port.
486
*/
487
/*
488
* NB: isdigit(**av) => we've to check that next parameter is really an
489
* option for this redirect entry, else stop here processing arg[cv].
490
*/
491
if (*ac != 0 && isdigit(***av)) {
492
if (strchr(**av, ':') != NULL) {
493
if (StrToAddrAndPortRange(**av, &r->raddr, protoName,
494
&portRange) != 0)
495
errx(EX_DATAERR, "redirect_port: "
496
"invalid remote port range");
497
} else {
498
SETLOPORT(portRange, 0);
499
SETNUMPORTS(portRange, 1);
500
StrToAddr(**av, &r->raddr);
501
}
502
(*av)++; (*ac)--;
503
} else {
504
SETLOPORT(portRange, 0);
505
SETNUMPORTS(portRange, 1);
506
r->raddr.s_addr = INADDR_ANY;
507
}
508
r->rport = GETLOPORT(portRange);
509
r->rport_cnt = GETNUMPORTS(portRange);
510
511
/*
512
* Make sure port ranges match up, then add the redirect ports.
513
*/
514
if (numLocalPorts != r->pport_cnt)
515
errx(EX_DATAERR, "redirect_port: "
516
"port ranges must be equal in size");
517
518
/* Remote port range is allowed to be '0' which means all ports. */
519
if (r->rport_cnt != numLocalPorts &&
520
(r->rport_cnt != 1 || r->rport != 0))
521
errx(EX_DATAERR, "redirect_port: remote port must"
522
"be 0 or equal to local port range in size");
523
524
/* Setup LSNAT server pool. */
525
if (lsnat != NULL) {
526
struct nat44_cfg_spool *spool;
527
528
sep = strtok(lsnat, ",");
529
while (sep != NULL) {
530
spool = (struct nat44_cfg_spool *)buf;
531
space += sizeof(struct nat44_cfg_spool);
532
/*
533
* The sctp nat does not allow the port numbers to
534
* be mapped to new port numbers. Therefore, no ports
535
* are to be specified in the target port field.
536
*/
537
if (r->proto == IPPROTO_SCTP) {
538
if (strchr (sep, ':')) {
539
errx(EX_DATAERR, "redirect_port:"
540
"port numbers do not change in "
541
"sctp, so do not specify them as "
542
"part of the target");
543
} else {
544
StrToAddr(sep, &spool->addr);
545
spool->port = r->pport;
546
}
547
} else {
548
if (StrToAddrAndPortRange(sep, &spool->addr,
549
protoName, &portRange) != 0)
550
errx(EX_DATAERR, "redirect_port:"
551
"invalid local port range");
552
if (GETNUMPORTS(portRange) != 1)
553
errx(EX_DATAERR, "redirect_port: "
554
"local port must be single in "
555
"this context");
556
spool->port = GETLOPORT(portRange);
557
}
558
r->spool_cnt++;
559
/* Point to the next possible nat44_cfg_spool. */
560
buf = &buf[sizeof(struct nat44_cfg_spool)];
561
sep = strtok(NULL, ",");
562
}
563
}
564
565
return (space);
566
}
567
568
static int
569
setup_redir_proto(char *buf, int *ac, char ***av)
570
{
571
struct nat44_cfg_redir *r;
572
struct protoent *protoent;
573
size_t space;
574
575
r = (struct nat44_cfg_redir *)buf;
576
r->mode = REDIR_PROTO;
577
/* Skip nat44_cfg_redir at beginning of buf. */
578
buf = &buf[sizeof(struct nat44_cfg_redir)];
579
space = sizeof(struct nat44_cfg_redir);
580
581
/*
582
* Extract protocol.
583
*/
584
protoent = getprotobyname(**av);
585
if (protoent == NULL)
586
errx(EX_DATAERR, "redirect_proto: unknown protocol %s", **av);
587
else
588
r->proto = protoent->p_proto;
589
590
(*av)++; (*ac)--;
591
592
/*
593
* Extract local address.
594
*/
595
StrToAddr(**av, &r->laddr);
596
597
(*av)++; (*ac)--;
598
599
/*
600
* Extract optional public address.
601
*/
602
if (*ac == 0) {
603
r->paddr.s_addr = INADDR_ANY;
604
r->raddr.s_addr = INADDR_ANY;
605
} else {
606
/* see above in setup_redir_port() */
607
if (isdigit(***av)) {
608
StrToAddr(**av, &r->paddr);
609
(*av)++; (*ac)--;
610
611
/*
612
* Extract optional remote address.
613
*/
614
/* see above in setup_redir_port() */
615
if (*ac != 0 && isdigit(***av)) {
616
StrToAddr(**av, &r->raddr);
617
(*av)++; (*ac)--;
618
}
619
}
620
}
621
622
return (space);
623
}
624
625
static void
626
nat_show_log(struct nat44_cfg_nat *n, void *arg __unused)
627
{
628
char *buf;
629
630
buf = (char *)(n + 1);
631
if (buf[0] != '\0')
632
printf("nat %s: %s\n", n->name, buf);
633
}
634
635
static void
636
nat_show_cfg(struct nat44_cfg_nat *n, void *arg __unused)
637
{
638
struct nat44_cfg_redir *t;
639
struct nat44_cfg_spool *s;
640
caddr_t buf;
641
struct protoent *p;
642
uint32_t cnt;
643
int i, off;
644
645
buf = (caddr_t)n;
646
off = sizeof(*n);
647
printf("ipfw nat %s config", n->name);
648
if (strlen(n->if_name) != 0)
649
printf(" if %s", n->if_name);
650
else if (n->ip.s_addr != 0)
651
printf(" ip %s", inet_ntoa(n->ip));
652
while (n->mode != 0) {
653
if (n->mode & PKT_ALIAS_LOG) {
654
printf(" log");
655
n->mode &= ~PKT_ALIAS_LOG;
656
} else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
657
printf(" deny_in");
658
n->mode &= ~PKT_ALIAS_DENY_INCOMING;
659
} else if (n->mode & PKT_ALIAS_SAME_PORTS) {
660
printf(" same_ports");
661
n->mode &= ~PKT_ALIAS_SAME_PORTS;
662
} else if (n->mode & PKT_ALIAS_SKIP_GLOBAL) {
663
printf(" skip_global");
664
n->mode &= ~PKT_ALIAS_SKIP_GLOBAL;
665
} else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
666
printf(" unreg_only");
667
n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
668
} else if (n->mode & PKT_ALIAS_UNREGISTERED_CGN) {
669
printf(" unreg_cgn");
670
n->mode &= ~PKT_ALIAS_UNREGISTERED_CGN;
671
} else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
672
printf(" reset");
673
n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
674
} else if (n->mode & PKT_ALIAS_REVERSE) {
675
printf(" reverse");
676
n->mode &= ~PKT_ALIAS_REVERSE;
677
} else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
678
printf(" proxy_only");
679
n->mode &= ~PKT_ALIAS_PROXY_ONLY;
680
} else if (n->mode & PKT_ALIAS_UDP_EIM) {
681
printf(" udp_eim");
682
n->mode &= ~PKT_ALIAS_UDP_EIM;
683
}
684
}
685
/* Print all the redirect's data configuration. */
686
for (cnt = 0; cnt < n->redir_cnt; cnt++) {
687
t = (struct nat44_cfg_redir *)&buf[off];
688
off += sizeof(struct nat44_cfg_redir);
689
switch (t->mode) {
690
case REDIR_ADDR:
691
printf(" redirect_addr");
692
if (t->spool_cnt == 0)
693
printf(" %s", inet_ntoa(t->laddr));
694
else
695
for (i = 0; i < t->spool_cnt; i++) {
696
s = (struct nat44_cfg_spool *)&buf[off];
697
if (i)
698
printf(",");
699
else
700
printf(" ");
701
printf("%s", inet_ntoa(s->addr));
702
off += sizeof(struct nat44_cfg_spool);
703
}
704
printf(" %s", inet_ntoa(t->paddr));
705
break;
706
case REDIR_PORT:
707
p = getprotobynumber(t->proto);
708
printf(" redirect_port %s ", p->p_name);
709
if (!t->spool_cnt) {
710
printf("%s:%u", inet_ntoa(t->laddr), t->lport);
711
if (t->pport_cnt > 1)
712
printf("-%u", t->lport +
713
t->pport_cnt - 1);
714
} else
715
for (i=0; i < t->spool_cnt; i++) {
716
s = (struct nat44_cfg_spool *)&buf[off];
717
if (i)
718
printf(",");
719
printf("%s:%u", inet_ntoa(s->addr),
720
s->port);
721
off += sizeof(struct nat44_cfg_spool);
722
}
723
724
printf(" ");
725
if (t->paddr.s_addr)
726
printf("%s:", inet_ntoa(t->paddr));
727
printf("%u", t->pport);
728
if (!t->spool_cnt && t->pport_cnt > 1)
729
printf("-%u", t->pport + t->pport_cnt - 1);
730
731
if (t->raddr.s_addr) {
732
printf(" %s", inet_ntoa(t->raddr));
733
if (t->rport) {
734
printf(":%u", t->rport);
735
if (!t->spool_cnt && t->rport_cnt > 1)
736
printf("-%u", t->rport +
737
t->rport_cnt - 1);
738
}
739
}
740
break;
741
case REDIR_PROTO:
742
p = getprotobynumber(t->proto);
743
printf(" redirect_proto %s %s", p->p_name,
744
inet_ntoa(t->laddr));
745
if (t->paddr.s_addr != 0) {
746
printf(" %s", inet_ntoa(t->paddr));
747
if (t->raddr.s_addr)
748
printf(" %s", inet_ntoa(t->raddr));
749
}
750
break;
751
default:
752
errx(EX_DATAERR, "unknown redir mode");
753
break;
754
}
755
}
756
printf("\n");
757
}
758
759
static int
760
nat_port_alias_parse(char *str, u_short *lpout, u_short *hpout) {
761
long lp, hp;
762
char *ptr;
763
/* Lower port parsing */
764
lp = (long) strtol(str, &ptr, 10);
765
if (lp < 1024 || lp > 65535)
766
return 0;
767
if (!ptr || *ptr != '-')
768
return 0;
769
/* Upper port parsing */
770
hp = (long) strtol(ptr, &ptr, 10);
771
if (hp < 1024 || hp > 65535)
772
return 0;
773
if (ptr)
774
return 0;
775
776
*lpout = (u_short) lp;
777
*hpout = (u_short) hp;
778
return 1;
779
}
780
781
void
782
ipfw_config_nat(int ac, char **av)
783
{
784
ipfw_obj_header *oh;
785
struct nat44_cfg_nat *n; /* Nat instance configuration. */
786
int i, off, tok, ac1;
787
u_short lp, hp;
788
char *id, *buf, **av1, *end;
789
size_t len;
790
791
av++;
792
ac--;
793
/* Nat id. */
794
if (ac == 0)
795
errx(EX_DATAERR, "missing nat id");
796
id = *av;
797
i = (int)strtol(id, &end, 0);
798
if (i <= 0 || *end != '\0')
799
errx(EX_DATAERR, "illegal nat id: %s", id);
800
av++;
801
ac--;
802
if (ac == 0)
803
errx(EX_DATAERR, "missing option");
804
805
len = sizeof(*oh) + sizeof(*n);
806
ac1 = ac;
807
av1 = av;
808
while (ac1 > 0) {
809
tok = match_token(nat_params, *av1);
810
ac1--;
811
av1++;
812
switch (tok) {
813
case TOK_IP:
814
case TOK_IF:
815
case TOK_PORT_ALIAS:
816
ac1--;
817
av1++;
818
break;
819
case TOK_ALOG:
820
case TOK_DENY_INC:
821
case TOK_SAME_PORTS:
822
case TOK_SKIP_GLOBAL:
823
case TOK_UNREG_ONLY:
824
case TOK_UNREG_CGN:
825
case TOK_RESET_ADDR:
826
case TOK_ALIAS_REV:
827
case TOK_PROXY_ONLY:
828
case TOK_UDP_EIM:
829
break;
830
case TOK_REDIR_ADDR:
831
if (ac1 < 2)
832
errx(EX_DATAERR, "redirect_addr: "
833
"not enough arguments");
834
len += estimate_redir_addr(&ac1, &av1);
835
av1 += 2;
836
ac1 -= 2;
837
break;
838
case TOK_REDIR_PORT:
839
if (ac1 < 3)
840
errx(EX_DATAERR, "redirect_port: "
841
"not enough arguments");
842
av1++;
843
ac1--;
844
len += estimate_redir_port(&ac1, &av1);
845
av1 += 2;
846
ac1 -= 2;
847
/* Skip optional remoteIP/port */
848
if (ac1 != 0 && isdigit(**av1)) {
849
av1++;
850
ac1--;
851
}
852
break;
853
case TOK_REDIR_PROTO:
854
if (ac1 < 2)
855
errx(EX_DATAERR, "redirect_proto: "
856
"not enough arguments");
857
len += sizeof(struct nat44_cfg_redir);
858
av1 += 2;
859
ac1 -= 2;
860
/* Skip optional remoteIP/port */
861
if (ac1 != 0 && isdigit(**av1)) {
862
av1++;
863
ac1--;
864
}
865
if (ac1 != 0 && isdigit(**av1)) {
866
av1++;
867
ac1--;
868
}
869
break;
870
default:
871
errx(EX_DATAERR, "unrecognised option ``%s''", av1[-1]);
872
}
873
}
874
875
if ((buf = malloc(len)) == NULL)
876
errx(EX_OSERR, "malloc failed");
877
878
/* Offset in buf: save space for header at the beginning. */
879
off = sizeof(*oh) + sizeof(*n);
880
memset(buf, 0, len);
881
oh = (ipfw_obj_header *)buf;
882
n = (struct nat44_cfg_nat *)(oh + 1);
883
oh->ntlv.head.length = sizeof(oh->ntlv);
884
snprintf(oh->ntlv.name, sizeof(oh->ntlv.name), "%d", i);
885
snprintf(n->name, sizeof(n->name), "%d", i);
886
887
while (ac > 0) {
888
tok = match_token(nat_params, *av);
889
ac--;
890
av++;
891
switch (tok) {
892
case TOK_IP:
893
if (ac == 0)
894
errx(EX_DATAERR, "missing option");
895
if (!inet_aton(av[0], &(n->ip)))
896
errx(EX_DATAERR, "bad ip address ``%s''",
897
av[0]);
898
ac--;
899
av++;
900
break;
901
case TOK_IF:
902
if (ac == 0)
903
errx(EX_DATAERR, "missing option");
904
set_addr_dynamic(av[0], n);
905
ac--;
906
av++;
907
break;
908
case TOK_ALOG:
909
n->mode |= PKT_ALIAS_LOG;
910
break;
911
case TOK_DENY_INC:
912
n->mode |= PKT_ALIAS_DENY_INCOMING;
913
break;
914
case TOK_SAME_PORTS:
915
n->mode |= PKT_ALIAS_SAME_PORTS;
916
break;
917
case TOK_UNREG_ONLY:
918
n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
919
break;
920
case TOK_UNREG_CGN:
921
n->mode |= PKT_ALIAS_UNREGISTERED_CGN;
922
break;
923
case TOK_SKIP_GLOBAL:
924
n->mode |= PKT_ALIAS_SKIP_GLOBAL;
925
break;
926
case TOK_RESET_ADDR:
927
n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
928
break;
929
case TOK_ALIAS_REV:
930
n->mode |= PKT_ALIAS_REVERSE;
931
break;
932
case TOK_PROXY_ONLY:
933
n->mode |= PKT_ALIAS_PROXY_ONLY;
934
break;
935
case TOK_UDP_EIM:
936
n->mode |= PKT_ALIAS_UDP_EIM;
937
break;
938
/*
939
* All the setup_redir_* functions work directly in
940
* the final buffer, see above for details.
941
*/
942
case TOK_REDIR_ADDR:
943
case TOK_REDIR_PORT:
944
case TOK_REDIR_PROTO:
945
switch (tok) {
946
case TOK_REDIR_ADDR:
947
i = setup_redir_addr(&buf[off], &ac, &av);
948
break;
949
case TOK_REDIR_PORT:
950
i = setup_redir_port(&buf[off], &ac, &av);
951
break;
952
case TOK_REDIR_PROTO:
953
i = setup_redir_proto(&buf[off], &ac, &av);
954
break;
955
}
956
n->redir_cnt++;
957
off += i;
958
break;
959
case TOK_PORT_ALIAS:
960
if (ac == 0)
961
errx(EX_DATAERR, "missing option");
962
if (!nat_port_alias_parse(av[0], &lp, &hp))
963
errx(EX_DATAERR,
964
"You need a range of port(s) from 1024 <= x < 65536");
965
if (lp >= hp)
966
errx(EX_DATAERR,
967
"Upper port has to be greater than lower port");
968
n->alias_port_lo = lp;
969
n->alias_port_hi = hp;
970
ac--;
971
av++;
972
break;
973
}
974
}
975
if (n->mode & PKT_ALIAS_SAME_PORTS && n->alias_port_lo)
976
errx(EX_DATAERR, "same_ports and port_range cannot both be selected");
977
978
i = do_set3(IP_FW_NAT44_XCONFIG, &oh->opheader, len);
979
if (i != 0)
980
err(1, "setsockopt(%s)", "IP_FW_NAT44_XCONFIG");
981
982
if (!g_co.do_quiet) {
983
/* After every modification, we show the resultant rule. */
984
int _ac = 3;
985
const char *_av[] = {"show", "config", id};
986
ipfw_show_nat(_ac, (char **)(void *)_av);
987
}
988
}
989
990
static void
991
nat_fill_ntlv(ipfw_obj_ntlv *ntlv, int i)
992
{
993
994
ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */
995
ntlv->head.length = sizeof(ipfw_obj_ntlv);
996
ntlv->idx = 1;
997
ntlv->set = 0; /* not yet */
998
snprintf(ntlv->name, sizeof(ntlv->name), "%d", i);
999
}
1000
1001
int
1002
ipfw_delete_nat(int i)
1003
{
1004
ipfw_obj_header oh;
1005
int ret;
1006
1007
memset(&oh, 0, sizeof(oh));
1008
nat_fill_ntlv(&oh.ntlv, i);
1009
ret = do_set3(IP_FW_NAT44_DESTROY, &oh.opheader, sizeof(oh));
1010
if (ret == -1) {
1011
if (!g_co.do_quiet)
1012
warn("nat %u not available", i);
1013
return (EX_UNAVAILABLE);
1014
}
1015
return (EX_OK);
1016
}
1017
1018
struct nat_list_arg {
1019
uint16_t cmd;
1020
int is_all;
1021
};
1022
1023
static int
1024
nat_show_data(struct nat44_cfg_nat *cfg, void *arg)
1025
{
1026
struct nat_list_arg *nla;
1027
ipfw_obj_header *oh;
1028
1029
nla = (struct nat_list_arg *)arg;
1030
1031
switch (nla->cmd) {
1032
case IP_FW_NAT44_XGETCONFIG:
1033
if (nat_get_cmd(cfg->name, nla->cmd, &oh) != 0) {
1034
warnx("Error getting nat instance %s info", cfg->name);
1035
break;
1036
}
1037
nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL);
1038
free(oh);
1039
break;
1040
case IP_FW_NAT44_XGETLOG:
1041
if (nat_get_cmd(cfg->name, nla->cmd, &oh) == 0) {
1042
nat_show_log((struct nat44_cfg_nat *)(oh + 1), NULL);
1043
free(oh);
1044
break;
1045
}
1046
/* Handle error */
1047
if (nla->is_all != 0 && errno == ENOENT)
1048
break;
1049
warn("Error getting nat instance %s info", cfg->name);
1050
break;
1051
}
1052
1053
return (0);
1054
}
1055
1056
/*
1057
* Compare nat names.
1058
* Honor number comparison.
1059
*/
1060
static int
1061
natname_cmp(const void *a, const void *b)
1062
{
1063
const struct nat44_cfg_nat *ia, *ib;
1064
1065
ia = (const struct nat44_cfg_nat *)a;
1066
ib = (const struct nat44_cfg_nat *)b;
1067
1068
return (stringnum_cmp(ia->name, ib->name));
1069
}
1070
1071
/*
1072
* Retrieves nat list from kernel,
1073
* optionally sorts it and calls requested function for each table.
1074
* Returns 0 on success.
1075
*/
1076
static int
1077
nat_foreach(nat_cb_t *f, void *arg, int sort)
1078
{
1079
ipfw_obj_lheader *olh;
1080
struct nat44_cfg_nat *cfg;
1081
size_t sz;
1082
uint32_t i;
1083
1084
/* Start with reasonable default */
1085
sz = sizeof(*olh) + 16 * sizeof(struct nat44_cfg_nat);
1086
1087
for (;;) {
1088
if ((olh = calloc(1, sz)) == NULL)
1089
return (ENOMEM);
1090
1091
olh->size = sz;
1092
if (do_get3(IP_FW_NAT44_LIST_NAT, &olh->opheader, &sz) != 0) {
1093
sz = olh->size;
1094
free(olh);
1095
if (errno == ENOMEM)
1096
continue;
1097
return (errno);
1098
}
1099
1100
if (sort != 0)
1101
qsort(olh + 1, olh->count, olh->objsize, natname_cmp);
1102
1103
cfg = (struct nat44_cfg_nat*)(olh + 1);
1104
for (i = 0; i < olh->count; i++) {
1105
(void)f(cfg, arg); /* Ignore errors for now */
1106
cfg = (struct nat44_cfg_nat *)((caddr_t)cfg +
1107
olh->objsize);
1108
}
1109
1110
free(olh);
1111
break;
1112
}
1113
1114
return (0);
1115
}
1116
1117
static int
1118
nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh)
1119
{
1120
ipfw_obj_header *oh;
1121
struct nat44_cfg_nat *cfg;
1122
size_t sz;
1123
1124
/* Start with reasonable default */
1125
sz = sizeof(*oh) + sizeof(*cfg) + 128;
1126
1127
for (;;) {
1128
if ((oh = calloc(1, sz)) == NULL)
1129
return (ENOMEM);
1130
cfg = (struct nat44_cfg_nat *)(oh + 1);
1131
oh->ntlv.head.length = sizeof(oh->ntlv);
1132
strlcpy(oh->ntlv.name, name, sizeof(oh->ntlv.name));
1133
strlcpy(cfg->name, name, sizeof(cfg->name));
1134
1135
if (do_get3(cmd, &oh->opheader, &sz) != 0) {
1136
sz = cfg->size;
1137
free(oh);
1138
if (errno == ENOMEM)
1139
continue;
1140
return (errno);
1141
}
1142
1143
*ooh = oh;
1144
break;
1145
}
1146
1147
return (0);
1148
}
1149
1150
void
1151
ipfw_show_nat(int ac, char **av)
1152
{
1153
ipfw_obj_header *oh;
1154
char *name;
1155
int cmd;
1156
struct nat_list_arg nla;
1157
1158
ac--;
1159
av++;
1160
1161
if (g_co.test_only)
1162
return;
1163
1164
/* Parse parameters. */
1165
cmd = 0; /* XXX: Change to IP_FW_NAT44_XGETLOG @ MFC */
1166
name = NULL;
1167
for ( ; ac != 0; ac--, av++) {
1168
if (!strncmp(av[0], "config", strlen(av[0]))) {
1169
cmd = IP_FW_NAT44_XGETCONFIG;
1170
continue;
1171
}
1172
if (strcmp(av[0], "log") == 0) {
1173
cmd = IP_FW_NAT44_XGETLOG;
1174
continue;
1175
}
1176
if (name != NULL)
1177
err(EX_USAGE,"only one instance name may be specified");
1178
name = av[0];
1179
}
1180
1181
if (cmd == 0)
1182
errx(EX_USAGE, "Please specify action. Available: config,log");
1183
1184
if (name == NULL) {
1185
memset(&nla, 0, sizeof(nla));
1186
nla.cmd = cmd;
1187
nla.is_all = 1;
1188
nat_foreach(nat_show_data, &nla, 1);
1189
} else {
1190
if (nat_get_cmd(name, cmd, &oh) != 0)
1191
err(EX_OSERR, "Error getting nat %s instance info", name);
1192
nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL);
1193
free(oh);
1194
}
1195
}
1196
1197
1198