1187770Sluigi/*
2187770Sluigi * Copyright (c) 2002-2003 Luigi Rizzo
3187770Sluigi * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4187770Sluigi * Copyright (c) 1994 Ugen J.S.Antsilevich
5187770Sluigi *
6187770Sluigi * Idea and grammar partially left from:
7187770Sluigi * Copyright (c) 1993 Daniel Boulet
8187770Sluigi *
9187770Sluigi * Redistribution and use in source forms, with and without modification,
10187770Sluigi * are permitted provided that this entire comment appears intact.
11187770Sluigi *
12187770Sluigi * Redistribution in binary form may occur without any restrictions.
13187770Sluigi * Obviously, it would be nice if you gave credit where credit is due
14187770Sluigi * but requiring it would be too onerous.
15187770Sluigi *
16187770Sluigi * This software is provided ``AS IS'' without any warranties of any kind.
17187770Sluigi *
18187770Sluigi * NEW command line interface for IP firewall facility
19187770Sluigi *
20187770Sluigi * $FreeBSD$
21187770Sluigi *
22187770Sluigi * In-kernel nat support
23187770Sluigi */
24187770Sluigi
25187770Sluigi#include <sys/types.h>
26187770Sluigi#include <sys/socket.h>
27187770Sluigi#include <sys/sysctl.h>
28187770Sluigi
29187770Sluigi#include "ipfw2.h"
30187770Sluigi
31187770Sluigi#include <ctype.h>
32187770Sluigi#include <err.h>
33187770Sluigi#include <netdb.h>
34187770Sluigi#include <stdio.h>
35187770Sluigi#include <stdlib.h>
36187770Sluigi#include <string.h>
37187770Sluigi#include <sysexits.h>
38187770Sluigi
39187770Sluigi#define IPFW_INTERNAL	/* Access to protected structures in ip_fw.h. */
40187770Sluigi
41187770Sluigi#include <net/if.h>
42187770Sluigi#include <net/if_dl.h>
43187770Sluigi#include <net/route.h> /* def. of struct route */
44187770Sluigi#include <netinet/in.h>
45187770Sluigi#include <netinet/ip_fw.h>
46187770Sluigi#include <arpa/inet.h>
47187770Sluigi#include <alias.h>
48187770Sluigi
49187770Sluigistatic struct _s_x nat_params[] = {
50220802Sglebius	{ "ip",			TOK_IP },
51220802Sglebius	{ "if",			TOK_IF },
52220802Sglebius 	{ "log",		TOK_ALOG },
53220802Sglebius 	{ "deny_in",		TOK_DENY_INC },
54220802Sglebius 	{ "same_ports",		TOK_SAME_PORTS },
55220802Sglebius 	{ "unreg_only",		TOK_UNREG_ONLY },
56223080Sae	{ "skip_global",	TOK_SKIP_GLOBAL },
57220802Sglebius 	{ "reset",		TOK_RESET_ADDR },
58220804Sglebius 	{ "reverse",		TOK_ALIAS_REV },
59220802Sglebius 	{ "proxy_only",		TOK_PROXY_ONLY },
60187770Sluigi	{ "redirect_addr",	TOK_REDIR_ADDR },
61187770Sluigi	{ "redirect_port",	TOK_REDIR_PORT },
62187770Sluigi	{ "redirect_proto",	TOK_REDIR_PROTO },
63187770Sluigi 	{ NULL, 0 }	/* terminator */
64187770Sluigi};
65187770Sluigi
66187770Sluigi
67220802Sglebius/*
68187770Sluigi * Search for interface with name "ifn", and fill n accordingly:
69187770Sluigi *
70220802Sglebius * n->ip	ip address of interface "ifn"
71187770Sluigi * n->if_name   copy of interface name "ifn"
72187770Sluigi */
73187770Sluigistatic void
74187770Sluigiset_addr_dynamic(const char *ifn, struct cfg_nat *n)
75187770Sluigi{
76187770Sluigi	size_t needed;
77187770Sluigi	int mib[6];
78187770Sluigi	char *buf, *lim, *next;
79187770Sluigi	struct if_msghdr *ifm;
80187770Sluigi	struct ifa_msghdr *ifam;
81187770Sluigi	struct sockaddr_dl *sdl;
82187770Sluigi	struct sockaddr_in *sin;
83187770Sluigi	int ifIndex, ifMTU;
84187770Sluigi
85187770Sluigi	mib[0] = CTL_NET;
86187770Sluigi	mib[1] = PF_ROUTE;
87187770Sluigi	mib[2] = 0;
88220804Sglebius	mib[3] = AF_INET;
89187770Sluigi	mib[4] = NET_RT_IFLIST;
90220804Sglebius	mib[5] = 0;
91187770Sluigi/*
92187770Sluigi * Get interface data.
93187770Sluigi */
94187770Sluigi	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
95187770Sluigi		err(1, "iflist-sysctl-estimate");
96187770Sluigi	buf = safe_calloc(1, needed);
97187770Sluigi	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
98187770Sluigi		err(1, "iflist-sysctl-get");
99187770Sluigi	lim = buf + needed;
100187770Sluigi/*
101187770Sluigi * Loop through interfaces until one with
102187770Sluigi * given name is found. This is done to
103187770Sluigi * find correct interface index for routing
104187770Sluigi * message processing.
105187770Sluigi */
106187770Sluigi	ifIndex	= 0;
107187770Sluigi	next = buf;
108187770Sluigi	while (next < lim) {
109187770Sluigi		ifm = (struct if_msghdr *)next;
110187770Sluigi		next += ifm->ifm_msglen;
111187770Sluigi		if (ifm->ifm_version != RTM_VERSION) {
112187770Sluigi			if (co.verbose)
113187770Sluigi				warnx("routing message version %d "
114187770Sluigi				    "not understood", ifm->ifm_version);
115187770Sluigi			continue;
116187770Sluigi		}
117187770Sluigi		if (ifm->ifm_type == RTM_IFINFO) {
118187770Sluigi			sdl = (struct sockaddr_dl *)(ifm + 1);
119187770Sluigi			if (strlen(ifn) == sdl->sdl_nlen &&
120187770Sluigi			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
121187770Sluigi				ifIndex = ifm->ifm_index;
122187770Sluigi				ifMTU = ifm->ifm_data.ifi_mtu;
123187770Sluigi				break;
124187770Sluigi			}
125187770Sluigi		}
126187770Sluigi	}
127187770Sluigi	if (!ifIndex)
128187770Sluigi		errx(1, "unknown interface name %s", ifn);
129187770Sluigi/*
130187770Sluigi * Get interface address.
131187770Sluigi */
132187770Sluigi	sin = NULL;
133187770Sluigi	while (next < lim) {
134187770Sluigi		ifam = (struct ifa_msghdr *)next;
135187770Sluigi		next += ifam->ifam_msglen;
136187770Sluigi		if (ifam->ifam_version != RTM_VERSION) {
137187770Sluigi			if (co.verbose)
138187770Sluigi				warnx("routing message version %d "
139187770Sluigi				    "not understood", ifam->ifam_version);
140187770Sluigi			continue;
141187770Sluigi		}
142187770Sluigi		if (ifam->ifam_type != RTM_NEWADDR)
143187770Sluigi			break;
144187770Sluigi		if (ifam->ifam_addrs & RTA_IFA) {
145187770Sluigi			int i;
146187770Sluigi			char *cp = (char *)(ifam + 1);
147187770Sluigi
148187770Sluigi			for (i = 1; i < RTA_IFA; i <<= 1) {
149187770Sluigi				if (ifam->ifam_addrs & i)
150187770Sluigi					cp += SA_SIZE((struct sockaddr *)cp);
151187770Sluigi			}
152187770Sluigi			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
153187770Sluigi				sin = (struct sockaddr_in *)cp;
154187770Sluigi				break;
155187770Sluigi			}
156187770Sluigi		}
157187770Sluigi	}
158187770Sluigi	if (sin == NULL)
159187770Sluigi		errx(1, "%s: cannot get interface address", ifn);
160187770Sluigi
161187770Sluigi	n->ip = sin->sin_addr;
162187770Sluigi	strncpy(n->if_name, ifn, IF_NAMESIZE);
163187770Sluigi
164187770Sluigi	free(buf);
165187770Sluigi}
166187770Sluigi
167220802Sglebius/*
168187770Sluigi * XXX - The following functions, macros and definitions come from natd.c:
169220802Sglebius * it would be better to move them outside natd.c, in a file
170220802Sglebius * (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live
171187770Sluigi * with it.
172187770Sluigi */
173187770Sluigi
174187770Sluigi/*
175187770Sluigi * Definition of a port range, and macros to deal with values.
176187770Sluigi * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
177220802Sglebius *	  LO 16-bits == number of ports in range
178187770Sluigi * NOTES:   - Port values are not stored in network byte order.
179187770Sluigi */
180187770Sluigi
181187770Sluigi#define port_range u_long
182187770Sluigi
183220802Sglebius#define GETLOPORT(x)	((x) >> 0x10)
184220802Sglebius#define GETNUMPORTS(x)	((x) & 0x0000ffff)
185220802Sglebius#define GETHIPORT(x)	(GETLOPORT((x)) + GETNUMPORTS((x)))
186187770Sluigi
187187770Sluigi/* Set y to be the low-port value in port_range variable x. */
188187770Sluigi#define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
189187770Sluigi
190187770Sluigi/* Set y to be the number of ports in port_range variable x. */
191187770Sluigi#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
192187770Sluigi
193220802Sglebiusstatic void
194187770SluigiStrToAddr (const char* str, struct in_addr* addr)
195187770Sluigi{
196187770Sluigi	struct hostent* hp;
197187770Sluigi
198187770Sluigi	if (inet_aton (str, addr))
199187770Sluigi		return;
200187770Sluigi
201187770Sluigi	hp = gethostbyname (str);
202187770Sluigi	if (!hp)
203187770Sluigi		errx (1, "unknown host %s", str);
204187770Sluigi
205187770Sluigi	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
206187770Sluigi}
207187770Sluigi
208220802Sglebiusstatic int
209187770SluigiStrToPortRange (const char* str, const char* proto, port_range *portRange)
210187770Sluigi{
211220802Sglebius	char*	   sep;
212187770Sluigi	struct servent*	sp;
213187770Sluigi	char*		end;
214220802Sglebius	u_short	 loPort;
215220802Sglebius	u_short	 hiPort;
216220804Sglebius
217187770Sluigi	/* First see if this is a service, return corresponding port if so. */
218187770Sluigi	sp = getservbyname (str,proto);
219187770Sluigi	if (sp) {
220220802Sglebius		SETLOPORT(*portRange, ntohs(sp->s_port));
221187770Sluigi		SETNUMPORTS(*portRange, 1);
222187770Sluigi		return 0;
223187770Sluigi	}
224220802Sglebius
225187770Sluigi	/* Not a service, see if it's a single port or port range. */
226187770Sluigi	sep = strchr (str, '-');
227187770Sluigi	if (sep == NULL) {
228220802Sglebius		SETLOPORT(*portRange, strtol(str, &end, 10));
229187770Sluigi		if (end != str) {
230220802Sglebius			/* Single port. */
231220802Sglebius			SETNUMPORTS(*portRange, 1);
232187770Sluigi			return 0;
233187770Sluigi		}
234187770Sluigi
235187770Sluigi		/* Error in port range field. */
236187770Sluigi		errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
237187770Sluigi	}
238187770Sluigi
239187770Sluigi	/* Port range, get the values and sanity check. */
240187770Sluigi	sscanf (str, "%hu-%hu", &loPort, &hiPort);
241187770Sluigi	SETLOPORT(*portRange, loPort);
242187770Sluigi	SETNUMPORTS(*portRange, 0);	/* Error by default */
243187770Sluigi	if (loPort <= hiPort)
244220802Sglebius		SETNUMPORTS(*portRange, hiPort - loPort + 1);
245187770Sluigi
246187770Sluigi	if (GETNUMPORTS(*portRange) == 0)
247220802Sglebius		errx (EX_DATAERR, "invalid port range %s", str);
248187770Sluigi
249187770Sluigi	return 0;
250187770Sluigi}
251187770Sluigi
252220802Sglebiusstatic int
253187770SluigiStrToProto (const char* str)
254187770Sluigi{
255187770Sluigi	if (!strcmp (str, "tcp"))
256187770Sluigi		return IPPROTO_TCP;
257187770Sluigi
258187770Sluigi	if (!strcmp (str, "udp"))
259187770Sluigi		return IPPROTO_UDP;
260187770Sluigi
261188294Spiso	if (!strcmp (str, "sctp"))
262188294Spiso		return IPPROTO_SCTP;
263188294Spiso	errx (EX_DATAERR, "unknown protocol %s. Expected sctp, tcp or udp", str);
264187770Sluigi}
265187770Sluigi
266220802Sglebiusstatic int
267220802SglebiusStrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto,
268220802Sglebius			port_range *portRange)
269187770Sluigi{
270187770Sluigi	char*	ptr;
271187770Sluigi
272187770Sluigi	ptr = strchr (str, ':');
273187770Sluigi	if (!ptr)
274187770Sluigi		errx (EX_DATAERR, "%s is missing port number", str);
275187770Sluigi
276187770Sluigi	*ptr = '\0';
277187770Sluigi	++ptr;
278187770Sluigi
279187770Sluigi	StrToAddr (str, addr);
280187770Sluigi	return StrToPortRange (ptr, proto, portRange);
281187770Sluigi}
282187770Sluigi
283187770Sluigi/* End of stuff taken from natd.c. */
284187770Sluigi
285220802Sglebius/*
286220802Sglebius * The next 3 functions add support for the addr, port and proto redirect and
287220802Sglebius * their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect()
288187770Sluigi * and SetupProtoRedirect() from natd.c.
289187770Sluigi *
290220802Sglebius * Every setup_* function fills at least one redirect entry
291220802Sglebius * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool)
292187770Sluigi * in buf.
293220802Sglebius *
294187770Sluigi * The format of data in buf is:
295187770Sluigi *
296220802Sglebius *     cfg_nat    cfg_redir    cfg_spool    ......  cfg_spool
297187770Sluigi *
298187770Sluigi *    -------------------------------------        ------------
299187770Sluigi *   |          | .....X ... |          |         |           |  .....
300187770Sluigi *    ------------------------------------- ...... ------------
301220802Sglebius *                     ^
302187770Sluigi *                spool_cnt       n=0       ......   n=(X-1)
303187770Sluigi *
304187770Sluigi * len points to the amount of available space in buf
305187770Sluigi * space counts the memory consumed by every function
306187770Sluigi *
307220802Sglebius * XXX - Every function get all the argv params so it
308187770Sluigi * has to check, in optional parameters, that the next
309220802Sglebius * args is a valid option for the redir entry and not
310220802Sglebius * another token. Only redir_port and redir_proto are
311187770Sluigi * affected by this.
312187770Sluigi */
313187770Sluigi
314187770Sluigistatic int
315220835Sglebiusestimate_redir_addr(int *ac, char ***av)
316187770Sluigi{
317220835Sglebius	size_t space = sizeof(struct cfg_redir);
318223185Sglebius	char *sep = **av;
319223185Sglebius	u_int c = 0;
320220835Sglebius
321223185Sglebius	while ((sep = strchr(sep, ',')) != NULL) {
322223185Sglebius		c++;
323223185Sglebius		sep++;
324220835Sglebius	}
325220835Sglebius
326223185Sglebius	if (c > 0)
327223185Sglebius		c++;
328223185Sglebius
329223185Sglebius	space += c * sizeof(struct cfg_spool);
330223185Sglebius
331220835Sglebius	return (space);
332220835Sglebius}
333220835Sglebius
334220835Sglebiusstatic int
335220835Sglebiussetup_redir_addr(char *buf, int *ac, char ***av)
336220835Sglebius{
337220804Sglebius	struct cfg_redir *r;
338220835Sglebius	char *sep;
339220835Sglebius	size_t space;
340187770Sluigi
341220835Sglebius	r = (struct cfg_redir *)buf;
342187770Sluigi	r->mode = REDIR_ADDR;
343220835Sglebius	/* Skip cfg_redir at beginning of buf. */
344220835Sglebius	buf = &buf[sizeof(struct cfg_redir)];
345220835Sglebius	space = sizeof(struct cfg_redir);
346220835Sglebius
347187770Sluigi	/* Extract local address. */
348228051Sglebius	if (strchr(**av, ',') != NULL) {
349220835Sglebius		struct cfg_spool *spool;
350220835Sglebius
351220835Sglebius		/* Setup LSNAT server pool. */
352187770Sluigi		r->laddr.s_addr = INADDR_NONE;
353228051Sglebius		sep = strtok(**av, ",");
354187770Sluigi		while (sep != NULL) {
355220835Sglebius			spool = (struct cfg_spool *)buf;
356220835Sglebius			space += sizeof(struct cfg_spool);
357220835Sglebius			StrToAddr(sep, &spool->addr);
358220835Sglebius			spool->port = ~0;
359187770Sluigi			r->spool_cnt++;
360187770Sluigi			/* Point to the next possible cfg_spool. */
361220835Sglebius			buf = &buf[sizeof(struct cfg_spool)];
362187770Sluigi			sep = strtok(NULL, ",");
363187770Sluigi		}
364220835Sglebius	} else
365220835Sglebius		StrToAddr(**av, &r->laddr);
366220835Sglebius	(*av)++; (*ac)--;
367220835Sglebius
368220835Sglebius	/* Extract public address. */
369220835Sglebius	StrToAddr(**av, &r->paddr);
370220835Sglebius	(*av)++; (*ac)--;
371220835Sglebius
372220835Sglebius	return (space);
373220835Sglebius}
374220835Sglebius
375220835Sglebiusstatic int
376220835Sglebiusestimate_redir_port(int *ac, char ***av)
377220835Sglebius{
378220835Sglebius	size_t space = sizeof(struct cfg_redir);
379223185Sglebius	char *sep = **av;
380223185Sglebius	u_int c = 0;
381220835Sglebius
382223185Sglebius	while ((sep = strchr(sep, ',')) != NULL) {
383223185Sglebius		c++;
384223185Sglebius		sep++;
385187770Sluigi	}
386220835Sglebius
387223185Sglebius	if (c > 0)
388223185Sglebius		c++;
389223185Sglebius
390223185Sglebius	space += c * sizeof(struct cfg_spool);
391223185Sglebius
392220835Sglebius	return (space);
393187770Sluigi}
394187770Sluigi
395187770Sluigistatic int
396220835Sglebiussetup_redir_port(char *buf, int *ac, char ***av)
397187770Sluigi{
398187770Sluigi	struct cfg_redir *r;
399220835Sglebius	char *sep, *protoName, *lsnat = NULL;
400220835Sglebius	size_t space;
401187770Sluigi	u_short numLocalPorts;
402220804Sglebius	port_range portRange;
403187770Sluigi
404220804Sglebius	numLocalPorts = 0;
405187770Sluigi
406220835Sglebius	r = (struct cfg_redir *)buf;
407187770Sluigi	r->mode = REDIR_PORT;
408220835Sglebius	/* Skip cfg_redir at beginning of buf. */
409220835Sglebius	buf = &buf[sizeof(struct cfg_redir)];
410220835Sglebius	space = sizeof(struct cfg_redir);
411220835Sglebius
412187770Sluigi	/*
413187770Sluigi	 * Extract protocol.
414187770Sluigi	 */
415220835Sglebius	r->proto = StrToProto(**av);
416220835Sglebius	protoName = **av;
417220835Sglebius	(*av)++; (*ac)--;
418187770Sluigi
419187770Sluigi	/*
420187770Sluigi	 * Extract local address.
421187770Sluigi	 */
422220835Sglebius	if ((sep = strchr(**av, ',')) != NULL) {
423187770Sluigi		r->laddr.s_addr = INADDR_NONE;
424187770Sluigi		r->lport = ~0;
425187770Sluigi		numLocalPorts = 1;
426220835Sglebius		lsnat = **av;
427187770Sluigi	} else {
428188294Spiso		/*
429220802Sglebius		 * The sctp nat does not allow the port numbers to be mapped to
430220802Sglebius		 * new port numbers. Therefore, no ports are to be specified
431188294Spiso		 * in the target port field.
432188294Spiso		 */
433188294Spiso		if (r->proto == IPPROTO_SCTP) {
434220835Sglebius			if (strchr(**av, ':'))
435188294Spiso				errx(EX_DATAERR, "redirect_port:"
436220835Sglebius				    "port numbers do not change in sctp, so do "
437220835Sglebius				    "not specify them as part of the target");
438188294Spiso			else
439220835Sglebius				StrToAddr(**av, &r->laddr);
440188294Spiso		} else {
441220835Sglebius			if (StrToAddrAndPortRange(**av, &r->laddr, protoName,
442220835Sglebius			    &portRange) != 0)
443220835Sglebius				errx(EX_DATAERR, "redirect_port: "
444188294Spiso				    "invalid local port range");
445187770Sluigi
446188294Spiso			r->lport = GETLOPORT(portRange);
447188294Spiso			numLocalPorts = GETNUMPORTS(portRange);
448188294Spiso		}
449187770Sluigi	}
450220835Sglebius	(*av)++; (*ac)--;
451187770Sluigi
452187770Sluigi	/*
453187770Sluigi	 * Extract public port and optionally address.
454187770Sluigi	 */
455220835Sglebius	if ((sep = strchr(**av, ':')) != NULL) {
456220835Sglebius		if (StrToAddrAndPortRange(**av, &r->paddr, protoName,
457187770Sluigi		    &portRange) != 0)
458220835Sglebius			errx(EX_DATAERR, "redirect_port: "
459187770Sluigi			    "invalid public port range");
460187770Sluigi	} else {
461187770Sluigi		r->paddr.s_addr = INADDR_ANY;
462220835Sglebius		if (StrToPortRange(**av, protoName, &portRange) != 0)
463220835Sglebius			errx(EX_DATAERR, "redirect_port: "
464187770Sluigi			    "invalid public port range");
465187770Sluigi	}
466187770Sluigi
467187770Sluigi	r->pport = GETLOPORT(portRange);
468188294Spiso	if (r->proto == IPPROTO_SCTP) { /* so the logic below still works */
469188294Spiso		numLocalPorts = GETNUMPORTS(portRange);
470188294Spiso		r->lport = r->pport;
471188294Spiso	}
472187770Sluigi	r->pport_cnt = GETNUMPORTS(portRange);
473220835Sglebius	(*av)++; (*ac)--;
474187770Sluigi
475187770Sluigi	/*
476187770Sluigi	 * Extract remote address and optionally port.
477220804Sglebius	 */
478220802Sglebius	/*
479223185Sglebius	 * NB: isdigit(**av) => we've to check that next parameter is really an
480187770Sluigi	 * option for this redirect entry, else stop here processing arg[cv].
481187770Sluigi	 */
482223185Sglebius	if (*ac != 0 && isdigit(***av)) {
483220835Sglebius		if ((sep = strchr(**av, ':')) != NULL) {
484220835Sglebius			if (StrToAddrAndPortRange(**av, &r->raddr, protoName,
485187770Sluigi			    &portRange) != 0)
486220835Sglebius				errx(EX_DATAERR, "redirect_port: "
487187770Sluigi				    "invalid remote port range");
488187770Sluigi		} else {
489220802Sglebius			SETLOPORT(portRange, 0);
490187770Sluigi			SETNUMPORTS(portRange, 1);
491220835Sglebius			StrToAddr(**av, &r->raddr);
492187770Sluigi		}
493220835Sglebius		(*av)++; (*ac)--;
494187770Sluigi	} else {
495187770Sluigi		SETLOPORT(portRange, 0);
496187770Sluigi		SETNUMPORTS(portRange, 1);
497187770Sluigi		r->raddr.s_addr = INADDR_ANY;
498187770Sluigi	}
499187770Sluigi	r->rport = GETLOPORT(portRange);
500187770Sluigi	r->rport_cnt = GETNUMPORTS(portRange);
501187770Sluigi
502220802Sglebius	/*
503187770Sluigi	 * Make sure port ranges match up, then add the redirect ports.
504187770Sluigi	 */
505187770Sluigi	if (numLocalPorts != r->pport_cnt)
506220835Sglebius		errx(EX_DATAERR, "redirect_port: "
507187770Sluigi		    "port ranges must be equal in size");
508187770Sluigi
509187770Sluigi	/* Remote port range is allowed to be '0' which means all ports. */
510220802Sglebius	if (r->rport_cnt != numLocalPorts &&
511187770Sluigi	    (r->rport_cnt != 1 || r->rport != 0))
512220802Sglebius		errx(EX_DATAERR, "redirect_port: remote port must"
513187770Sluigi		    "be 0 or equal to local port range in size");
514187770Sluigi
515220835Sglebius	/* Setup LSNAT server pool. */
516220835Sglebius	if (lsnat != NULL) {
517220835Sglebius		struct cfg_spool *spool;
518220835Sglebius
519220835Sglebius		sep = strtok(lsnat, ",");
520187770Sluigi		while (sep != NULL) {
521220835Sglebius			spool = (struct cfg_spool *)buf;
522220835Sglebius			space += sizeof(struct cfg_spool);
523188294Spiso			/*
524220835Sglebius			 * The sctp nat does not allow the port numbers to
525220835Sglebius			 * be mapped to new port numbers. Therefore, no ports
526220835Sglebius			 * are to be specified in the target port field.
527188294Spiso			 */
528188294Spiso			if (r->proto == IPPROTO_SCTP) {
529188294Spiso				if (strchr (sep, ':')) {
530188294Spiso					errx(EX_DATAERR, "redirect_port:"
531188294Spiso					    "port numbers do not change in "
532188294Spiso					    "sctp, so do not specify them as "
533188294Spiso					    "part of the target");
534188294Spiso				} else {
535220835Sglebius					StrToAddr(sep, &spool->addr);
536220835Sglebius					spool->port = r->pport;
537188294Spiso				}
538188294Spiso			} else {
539220835Sglebius				if (StrToAddrAndPortRange(sep, &spool->addr,
540188294Spiso					protoName, &portRange) != 0)
541188294Spiso					errx(EX_DATAERR, "redirect_port:"
542188294Spiso					    "invalid local port range");
543188294Spiso				if (GETNUMPORTS(portRange) != 1)
544188294Spiso					errx(EX_DATAERR, "redirect_port: "
545188294Spiso					    "local port must be single in "
546188294Spiso					    "this context");
547220835Sglebius				spool->port = GETLOPORT(portRange);
548188294Spiso			}
549220804Sglebius			r->spool_cnt++;
550187770Sluigi			/* Point to the next possible cfg_spool. */
551220835Sglebius			buf = &buf[sizeof(struct cfg_spool)];
552187770Sluigi			sep = strtok(NULL, ",");
553187770Sluigi		}
554187770Sluigi	}
555220835Sglebius
556187770Sluigi	return (space);
557187770Sluigi}
558187770Sluigi
559187770Sluigistatic int
560220835Sglebiussetup_redir_proto(char *buf, int *ac, char ***av)
561187770Sluigi{
562220835Sglebius	struct cfg_redir *r;
563187770Sluigi	struct protoent *protoent;
564220835Sglebius	size_t space;
565220804Sglebius
566220835Sglebius	r = (struct cfg_redir *)buf;
567187770Sluigi	r->mode = REDIR_PROTO;
568220835Sglebius	/* Skip cfg_redir at beginning of buf. */
569220835Sglebius	buf = &buf[sizeof(struct cfg_redir)];
570220835Sglebius	space = sizeof(struct cfg_redir);
571220835Sglebius
572187770Sluigi	/*
573187770Sluigi	 * Extract protocol.
574220804Sglebius	 */
575220835Sglebius	protoent = getprotobyname(**av);
576187770Sluigi	if (protoent == NULL)
577220835Sglebius		errx(EX_DATAERR, "redirect_proto: unknown protocol %s", **av);
578187770Sluigi	else
579187770Sluigi		r->proto = protoent->p_proto;
580187770Sluigi
581220835Sglebius	(*av)++; (*ac)--;
582220804Sglebius
583187770Sluigi	/*
584187770Sluigi	 * Extract local address.
585187770Sluigi	 */
586220835Sglebius	StrToAddr(**av, &r->laddr);
587187770Sluigi
588220835Sglebius	(*av)++; (*ac)--;
589220804Sglebius
590187770Sluigi	/*
591187770Sluigi	 * Extract optional public address.
592187770Sluigi	 */
593220835Sglebius	if (*ac == 0) {
594220804Sglebius		r->paddr.s_addr = INADDR_ANY;
595220804Sglebius		r->raddr.s_addr = INADDR_ANY;
596187770Sluigi	} else {
597187770Sluigi		/* see above in setup_redir_port() */
598223185Sglebius		if (isdigit(***av)) {
599220835Sglebius			StrToAddr(**av, &r->paddr);
600220835Sglebius			(*av)++; (*ac)--;
601220804Sglebius
602187770Sluigi			/*
603187770Sluigi			 * Extract optional remote address.
604220804Sglebius			 */
605187770Sluigi			/* see above in setup_redir_port() */
606223185Sglebius			if (*ac != 0 && isdigit(***av)) {
607220835Sglebius				StrToAddr(**av, &r->raddr);
608220835Sglebius				(*av)++; (*ac)--;
609187770Sluigi			}
610220804Sglebius		}
611187770Sluigi	}
612220835Sglebius
613187770Sluigi	return (space);
614187770Sluigi}
615187770Sluigi
616187770Sluigistatic void
617187770Sluigiprint_nat_config(unsigned char *buf)
618187770Sluigi{
619187770Sluigi	struct cfg_nat *n;
620187770Sluigi	int i, cnt, flag, off;
621187770Sluigi	struct cfg_redir *t;
622187770Sluigi	struct cfg_spool *s;
623187770Sluigi	struct protoent *p;
624187770Sluigi
625187770Sluigi	n = (struct cfg_nat *)buf;
626187770Sluigi	flag = 1;
627187770Sluigi	off  = sizeof(*n);
628187770Sluigi	printf("ipfw nat %u config", n->id);
629187770Sluigi	if (strlen(n->if_name) != 0)
630187770Sluigi		printf(" if %s", n->if_name);
631187770Sluigi	else if (n->ip.s_addr != 0)
632187770Sluigi		printf(" ip %s", inet_ntoa(n->ip));
633187770Sluigi	while (n->mode != 0) {
634187770Sluigi		if (n->mode & PKT_ALIAS_LOG) {
635187770Sluigi			printf(" log");
636187770Sluigi			n->mode &= ~PKT_ALIAS_LOG;
637187770Sluigi		} else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
638187770Sluigi			printf(" deny_in");
639187770Sluigi			n->mode &= ~PKT_ALIAS_DENY_INCOMING;
640187770Sluigi		} else if (n->mode & PKT_ALIAS_SAME_PORTS) {
641187770Sluigi			printf(" same_ports");
642187770Sluigi			n->mode &= ~PKT_ALIAS_SAME_PORTS;
643223080Sae		} else if (n->mode & PKT_ALIAS_SKIP_GLOBAL) {
644223080Sae			printf(" skip_global");
645223080Sae			n->mode &= ~PKT_ALIAS_SKIP_GLOBAL;
646187770Sluigi		} else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
647187770Sluigi			printf(" unreg_only");
648187770Sluigi			n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
649187770Sluigi		} else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
650187770Sluigi			printf(" reset");
651187770Sluigi			n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
652187770Sluigi		} else if (n->mode & PKT_ALIAS_REVERSE) {
653187770Sluigi			printf(" reverse");
654187770Sluigi			n->mode &= ~PKT_ALIAS_REVERSE;
655187770Sluigi		} else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
656187770Sluigi			printf(" proxy_only");
657187770Sluigi			n->mode &= ~PKT_ALIAS_PROXY_ONLY;
658187770Sluigi		}
659187770Sluigi	}
660187770Sluigi	/* Print all the redirect's data configuration. */
661187770Sluigi	for (cnt = 0; cnt < n->redir_cnt; cnt++) {
662187770Sluigi		t = (struct cfg_redir *)&buf[off];
663187770Sluigi		off += SOF_REDIR;
664187770Sluigi		switch (t->mode) {
665187770Sluigi		case REDIR_ADDR:
666187770Sluigi			printf(" redirect_addr");
667187770Sluigi			if (t->spool_cnt == 0)
668187770Sluigi				printf(" %s", inet_ntoa(t->laddr));
669187770Sluigi			else
670187770Sluigi				for (i = 0; i < t->spool_cnt; i++) {
671187770Sluigi					s = (struct cfg_spool *)&buf[off];
672187770Sluigi					if (i)
673187770Sluigi						printf(",");
674220802Sglebius					else
675187770Sluigi						printf(" ");
676187770Sluigi					printf("%s", inet_ntoa(s->addr));
677187770Sluigi					off += SOF_SPOOL;
678187770Sluigi				}
679187770Sluigi			printf(" %s", inet_ntoa(t->paddr));
680187770Sluigi			break;
681187770Sluigi		case REDIR_PORT:
682187770Sluigi			p = getprotobynumber(t->proto);
683187770Sluigi			printf(" redirect_port %s ", p->p_name);
684187770Sluigi			if (!t->spool_cnt) {
685187770Sluigi				printf("%s:%u", inet_ntoa(t->laddr), t->lport);
686187770Sluigi				if (t->pport_cnt > 1)
687220802Sglebius					printf("-%u", t->lport +
688187770Sluigi					    t->pport_cnt - 1);
689187770Sluigi			} else
690187770Sluigi				for (i=0; i < t->spool_cnt; i++) {
691187770Sluigi					s = (struct cfg_spool *)&buf[off];
692187770Sluigi					if (i)
693187770Sluigi						printf(",");
694220802Sglebius					printf("%s:%u", inet_ntoa(s->addr),
695187770Sluigi					    s->port);
696187770Sluigi					off += SOF_SPOOL;
697187770Sluigi				}
698187770Sluigi
699187770Sluigi			printf(" ");
700187770Sluigi			if (t->paddr.s_addr)
701220802Sglebius				printf("%s:", inet_ntoa(t->paddr));
702187770Sluigi			printf("%u", t->pport);
703187770Sluigi			if (!t->spool_cnt && t->pport_cnt > 1)
704187770Sluigi				printf("-%u", t->pport + t->pport_cnt - 1);
705187770Sluigi
706187770Sluigi			if (t->raddr.s_addr) {
707187770Sluigi				printf(" %s", inet_ntoa(t->raddr));
708187770Sluigi				if (t->rport) {
709187770Sluigi					printf(":%u", t->rport);
710187770Sluigi					if (!t->spool_cnt && t->rport_cnt > 1)
711220802Sglebius						printf("-%u", t->rport +
712187770Sluigi						    t->rport_cnt - 1);
713187770Sluigi				}
714187770Sluigi			}
715187770Sluigi			break;
716187770Sluigi		case REDIR_PROTO:
717187770Sluigi			p = getprotobynumber(t->proto);
718220802Sglebius			printf(" redirect_proto %s %s", p->p_name,
719187770Sluigi			    inet_ntoa(t->laddr));
720187770Sluigi			if (t->paddr.s_addr != 0) {
721187770Sluigi				printf(" %s", inet_ntoa(t->paddr));
722187770Sluigi				if (t->raddr.s_addr)
723187770Sluigi					printf(" %s", inet_ntoa(t->raddr));
724187770Sluigi			}
725187770Sluigi			break;
726187770Sluigi		default:
727187770Sluigi			errx(EX_DATAERR, "unknown redir mode");
728187770Sluigi			break;
729187770Sluigi		}
730187770Sluigi	}
731187770Sluigi	printf("\n");
732187770Sluigi}
733187770Sluigi
734187770Sluigivoid
735187770Sluigiipfw_config_nat(int ac, char **av)
736187770Sluigi{
737220802Sglebius	struct cfg_nat *n;		/* Nat instance configuration. */
738220835Sglebius	int i, off, tok, ac1;
739223079Sae	char *id, *buf, **av1, *end;
740220835Sglebius	size_t len;
741220804Sglebius
742223499Sglebius	av++;
743223499Sglebius	ac--;
744187770Sluigi	/* Nat id. */
745223079Sae	if (ac == 0)
746187770Sluigi		errx(EX_DATAERR, "missing nat id");
747223079Sae	id = *av;
748223079Sae	i = (int)strtol(id, &end, 0);
749223079Sae	if (i <= 0 || *end != '\0')
750223079Sae		errx(EX_DATAERR, "illegal nat id: %s", id);
751223499Sglebius	av++;
752223499Sglebius	ac--;
753220802Sglebius	if (ac == 0)
754187770Sluigi		errx(EX_DATAERR, "missing option");
755187770Sluigi
756220835Sglebius	len = sizeof(struct cfg_nat);
757220835Sglebius	ac1 = ac;
758220835Sglebius	av1 = av;
759220835Sglebius	while (ac1 > 0) {
760220835Sglebius		tok = match_token(nat_params, *av1);
761223499Sglebius		ac1--;
762223499Sglebius		av1++;
763220835Sglebius		switch (tok) {
764220835Sglebius		case TOK_IP:
765220835Sglebius		case TOK_IF:
766223499Sglebius			ac1--;
767223499Sglebius			av1++;
768223080Sae			break;
769220835Sglebius		case TOK_ALOG:
770220835Sglebius		case TOK_DENY_INC:
771220835Sglebius		case TOK_SAME_PORTS:
772223080Sae		case TOK_SKIP_GLOBAL:
773220835Sglebius		case TOK_UNREG_ONLY:
774220835Sglebius		case TOK_RESET_ADDR:
775220835Sglebius		case TOK_ALIAS_REV:
776220835Sglebius		case TOK_PROXY_ONLY:
777220835Sglebius			break;
778220835Sglebius		case TOK_REDIR_ADDR:
779220835Sglebius			if (ac1 < 2)
780220835Sglebius				errx(EX_DATAERR, "redirect_addr: "
781220835Sglebius				    "not enough arguments");
782220835Sglebius			len += estimate_redir_addr(&ac1, &av1);
783223499Sglebius			av1 += 2;
784223499Sglebius			ac1 -= 2;
785220835Sglebius			break;
786220835Sglebius		case TOK_REDIR_PORT:
787220835Sglebius			if (ac1 < 3)
788220835Sglebius				errx(EX_DATAERR, "redirect_port: "
789220835Sglebius				    "not enough arguments");
790223499Sglebius			av1++;
791223499Sglebius			ac1--;
792220835Sglebius			len += estimate_redir_port(&ac1, &av1);
793223499Sglebius			av1 += 2;
794223499Sglebius			ac1 -= 2;
795223185Sglebius			/* Skip optional remoteIP/port */
796223416Sglebius			if (ac1 != 0 && isdigit(**av1)) {
797223499Sglebius				av1++;
798223499Sglebius				ac1--;
799223416Sglebius			}
800220835Sglebius			break;
801220835Sglebius		case TOK_REDIR_PROTO:
802220835Sglebius			if (ac1 < 2)
803220835Sglebius				errx(EX_DATAERR, "redirect_proto: "
804220835Sglebius				    "not enough arguments");
805220835Sglebius			len += sizeof(struct cfg_redir);
806223499Sglebius			av1 += 2;
807223499Sglebius			ac1 -= 2;
808223185Sglebius			/* Skip optional remoteIP/port */
809223416Sglebius			if (ac1 != 0 && isdigit(**av1)) {
810223499Sglebius				av1++;
811223499Sglebius				ac1--;
812223416Sglebius			}
813223416Sglebius			if (ac1 != 0 && isdigit(**av1)) {
814223499Sglebius				av1++;
815223499Sglebius				ac1--;
816223416Sglebius			}
817220835Sglebius			break;
818220835Sglebius		default:
819220835Sglebius			errx(EX_DATAERR, "unrecognised option ``%s''", av1[-1]);
820220835Sglebius		}
821220835Sglebius	}
822220835Sglebius
823220835Sglebius	if ((buf = malloc(len)) == NULL)
824220835Sglebius		errx(EX_OSERR, "malloc failed");
825220835Sglebius
826220835Sglebius	/* Offset in buf: save space for n at the beginning. */
827220835Sglebius	off = sizeof(*n);
828220835Sglebius	memset(buf, 0, len);
829220835Sglebius	n = (struct cfg_nat *)buf;
830220835Sglebius	n->id = i;
831220835Sglebius
832187770Sluigi	while (ac > 0) {
833187770Sluigi		tok = match_token(nat_params, *av);
834223499Sglebius		ac--;
835223499Sglebius		av++;
836187770Sluigi		switch (tok) {
837187770Sluigi		case TOK_IP:
838220802Sglebius			if (ac == 0)
839187770Sluigi				errx(EX_DATAERR, "missing option");
840187770Sluigi			if (!inet_aton(av[0], &(n->ip)))
841220802Sglebius				errx(EX_DATAERR, "bad ip address ``%s''",
842187770Sluigi				    av[0]);
843223499Sglebius			ac--;
844223499Sglebius			av++;
845220802Sglebius			break;
846187770Sluigi		case TOK_IF:
847220802Sglebius			if (ac == 0)
848187770Sluigi				errx(EX_DATAERR, "missing option");
849187770Sluigi			set_addr_dynamic(av[0], n);
850223499Sglebius			ac--;
851223499Sglebius			av++;
852187770Sluigi			break;
853187770Sluigi		case TOK_ALOG:
854187770Sluigi			n->mode |= PKT_ALIAS_LOG;
855187770Sluigi			break;
856187770Sluigi		case TOK_DENY_INC:
857187770Sluigi			n->mode |= PKT_ALIAS_DENY_INCOMING;
858187770Sluigi			break;
859187770Sluigi		case TOK_SAME_PORTS:
860187770Sluigi			n->mode |= PKT_ALIAS_SAME_PORTS;
861187770Sluigi			break;
862187770Sluigi		case TOK_UNREG_ONLY:
863187770Sluigi			n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
864187770Sluigi			break;
865223080Sae		case TOK_SKIP_GLOBAL:
866223080Sae			n->mode |= PKT_ALIAS_SKIP_GLOBAL;
867223080Sae			break;
868187770Sluigi		case TOK_RESET_ADDR:
869187770Sluigi			n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
870187770Sluigi			break;
871187770Sluigi		case TOK_ALIAS_REV:
872187770Sluigi			n->mode |= PKT_ALIAS_REVERSE;
873187770Sluigi			break;
874187770Sluigi		case TOK_PROXY_ONLY:
875187770Sluigi			n->mode |= PKT_ALIAS_PROXY_ONLY;
876187770Sluigi			break;
877220802Sglebius			/*
878220802Sglebius			 * All the setup_redir_* functions work directly in
879220802Sglebius			 * the final buffer, see above for details.
880187770Sluigi			 */
881187770Sluigi		case TOK_REDIR_ADDR:
882187770Sluigi		case TOK_REDIR_PORT:
883187770Sluigi		case TOK_REDIR_PROTO:
884187770Sluigi			switch (tok) {
885187770Sluigi			case TOK_REDIR_ADDR:
886220835Sglebius				i = setup_redir_addr(&buf[off], &ac, &av);
887220802Sglebius				break;
888187770Sluigi			case TOK_REDIR_PORT:
889220835Sglebius				i = setup_redir_port(&buf[off], &ac, &av);
890220802Sglebius				break;
891187770Sluigi			case TOK_REDIR_PROTO:
892220835Sglebius				i = setup_redir_proto(&buf[off], &ac, &av);
893187770Sluigi				break;
894187770Sluigi			}
895187770Sluigi			n->redir_cnt++;
896187770Sluigi			off += i;
897187770Sluigi			break;
898187770Sluigi		}
899187770Sluigi	}
900187770Sluigi
901187770Sluigi	i = do_cmd(IP_FW_NAT_CFG, buf, off);
902187770Sluigi	if (i)
903187770Sluigi		err(1, "setsockopt(%s)", "IP_FW_NAT_CFG");
904187770Sluigi
905187770Sluigi	if (!co.do_quiet) {
906187770Sluigi		/* After every modification, we show the resultant rule. */
907187770Sluigi		int _ac = 3;
908189395Sluigi		const char *_av[] = {"show", "config", id};
909189395Sluigi		ipfw_show_nat(_ac, (char **)(void *)_av);
910187770Sluigi	}
911187770Sluigi}
912187770Sluigi
913187770Sluigi
914187770Sluigivoid
915187770Sluigiipfw_show_nat(int ac, char **av)
916187770Sluigi{
917187770Sluigi	struct cfg_nat *n;
918187770Sluigi	struct cfg_redir *e;
919187770Sluigi	int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size;
920187770Sluigi	int nat_cnt, redir_cnt, r;
921187770Sluigi	uint8_t *data, *p;
922187770Sluigi	char *endptr;
923187770Sluigi
924187770Sluigi	do_rule = 0;
925187770Sluigi	nalloc = 1024;
926187770Sluigi	size = 0;
927187770Sluigi	data = NULL;
928187770Sluigi	frule = 0;
929187770Sluigi	lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */
930223499Sglebius	ac--;
931223499Sglebius	av++;
932187770Sluigi
933187770Sluigi	if (co.test_only)
934187770Sluigi		return;
935187770Sluigi
936187770Sluigi	/* Parse parameters. */
937187770Sluigi	for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) {
938187770Sluigi		if (!strncmp(av[0], "config", strlen(av[0]))) {
939220802Sglebius			cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1;
940187770Sluigi			continue;
941187770Sluigi		}
942187770Sluigi		/* Convert command line rule #. */
943187770Sluigi		frule = lrule = strtoul(av[0], &endptr, 10);
944187770Sluigi		if (*endptr == '-')
945187770Sluigi			lrule = strtoul(endptr+1, &endptr, 10);
946220804Sglebius		if (lrule == 0)
947187770Sluigi			err(EX_USAGE, "invalid rule number: %s", av[0]);
948187770Sluigi		do_rule = 1;
949187770Sluigi	}
950187770Sluigi
951187770Sluigi	nbytes = nalloc;
952187770Sluigi	while (nbytes >= nalloc) {
953187770Sluigi		nalloc = nalloc * 2;
954187770Sluigi		nbytes = nalloc;
955187770Sluigi		data = safe_realloc(data, nbytes);
956187770Sluigi		if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0)
957187770Sluigi			err(EX_OSERR, "getsockopt(IP_FW_GET_%s)",
958187770Sluigi			    (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG");
959187770Sluigi	}
960187770Sluigi	if (nbytes == 0)
961187770Sluigi		exit(0);
962187770Sluigi	if (do_cfg) {
963187770Sluigi		nat_cnt = *((int *)data);
964187770Sluigi		for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
965187770Sluigi			n = (struct cfg_nat *)&data[i];
966187770Sluigi			if (frule <= n->id && lrule >= n->id)
967187770Sluigi				print_nat_config(&data[i]);
968187770Sluigi			i += sizeof(struct cfg_nat);
969187770Sluigi			for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
970187770Sluigi				e = (struct cfg_redir *)&data[i];
971220802Sglebius				i += sizeof(struct cfg_redir) + e->spool_cnt *
972187770Sluigi				    sizeof(struct cfg_spool);
973187770Sluigi			}
974187770Sluigi		}
975187770Sluigi	} else {
976187770Sluigi		for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) {
977187770Sluigi			p = &data[i];
978187770Sluigi			if (p == data + nbytes)
979187770Sluigi				break;
980187770Sluigi			bcopy(p, &r, sizeof(int));
981187770Sluigi			if (do_rule) {
982187770Sluigi				if (!(frule <= r && lrule >= r))
983187770Sluigi					continue;
984187770Sluigi			}
985187770Sluigi			printf("nat %u: %s\n", r, p+sizeof(int));
986187770Sluigi		}
987187770Sluigi	}
988187770Sluigi}
989