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)
159278324Sjhb		n->ip.s_addr = htonl(INADDR_ANY);
160278324Sjhb	else
161278324Sjhb		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
321238900Sluigi	(void)ac;	/* UNUSED */
322223185Sglebius	while ((sep = strchr(sep, ',')) != NULL) {
323223185Sglebius		c++;
324223185Sglebius		sep++;
325220835Sglebius	}
326220835Sglebius
327223185Sglebius	if (c > 0)
328223185Sglebius		c++;
329223185Sglebius
330223185Sglebius	space += c * sizeof(struct cfg_spool);
331223185Sglebius
332220835Sglebius	return (space);
333220835Sglebius}
334220835Sglebius
335220835Sglebiusstatic int
336220835Sglebiussetup_redir_addr(char *buf, int *ac, char ***av)
337220835Sglebius{
338220804Sglebius	struct cfg_redir *r;
339220835Sglebius	char *sep;
340220835Sglebius	size_t space;
341187770Sluigi
342220835Sglebius	r = (struct cfg_redir *)buf;
343187770Sluigi	r->mode = REDIR_ADDR;
344220835Sglebius	/* Skip cfg_redir at beginning of buf. */
345220835Sglebius	buf = &buf[sizeof(struct cfg_redir)];
346220835Sglebius	space = sizeof(struct cfg_redir);
347220835Sglebius
348187770Sluigi	/* Extract local address. */
349227901Sglebius	if (strchr(**av, ',') != NULL) {
350220835Sglebius		struct cfg_spool *spool;
351220835Sglebius
352220835Sglebius		/* Setup LSNAT server pool. */
353187770Sluigi		r->laddr.s_addr = INADDR_NONE;
354227901Sglebius		sep = strtok(**av, ",");
355187770Sluigi		while (sep != NULL) {
356220835Sglebius			spool = (struct cfg_spool *)buf;
357220835Sglebius			space += sizeof(struct cfg_spool);
358220835Sglebius			StrToAddr(sep, &spool->addr);
359220835Sglebius			spool->port = ~0;
360187770Sluigi			r->spool_cnt++;
361187770Sluigi			/* Point to the next possible cfg_spool. */
362220835Sglebius			buf = &buf[sizeof(struct cfg_spool)];
363187770Sluigi			sep = strtok(NULL, ",");
364187770Sluigi		}
365220835Sglebius	} else
366220835Sglebius		StrToAddr(**av, &r->laddr);
367220835Sglebius	(*av)++; (*ac)--;
368220835Sglebius
369220835Sglebius	/* Extract public address. */
370220835Sglebius	StrToAddr(**av, &r->paddr);
371220835Sglebius	(*av)++; (*ac)--;
372220835Sglebius
373220835Sglebius	return (space);
374220835Sglebius}
375220835Sglebius
376220835Sglebiusstatic int
377220835Sglebiusestimate_redir_port(int *ac, char ***av)
378220835Sglebius{
379220835Sglebius	size_t space = sizeof(struct cfg_redir);
380223185Sglebius	char *sep = **av;
381223185Sglebius	u_int c = 0;
382220835Sglebius
383238900Sluigi	(void)ac;	/* UNUSED */
384223185Sglebius	while ((sep = strchr(sep, ',')) != NULL) {
385223185Sglebius		c++;
386223185Sglebius		sep++;
387187770Sluigi	}
388220835Sglebius
389223185Sglebius	if (c > 0)
390223185Sglebius		c++;
391223185Sglebius
392223185Sglebius	space += c * sizeof(struct cfg_spool);
393223185Sglebius
394220835Sglebius	return (space);
395187770Sluigi}
396187770Sluigi
397187770Sluigistatic int
398220835Sglebiussetup_redir_port(char *buf, int *ac, char ***av)
399187770Sluigi{
400187770Sluigi	struct cfg_redir *r;
401220835Sglebius	char *sep, *protoName, *lsnat = NULL;
402220835Sglebius	size_t space;
403187770Sluigi	u_short numLocalPorts;
404220804Sglebius	port_range portRange;
405187770Sluigi
406220804Sglebius	numLocalPorts = 0;
407187770Sluigi
408220835Sglebius	r = (struct cfg_redir *)buf;
409187770Sluigi	r->mode = REDIR_PORT;
410220835Sglebius	/* Skip cfg_redir at beginning of buf. */
411220835Sglebius	buf = &buf[sizeof(struct cfg_redir)];
412220835Sglebius	space = sizeof(struct cfg_redir);
413220835Sglebius
414187770Sluigi	/*
415187770Sluigi	 * Extract protocol.
416187770Sluigi	 */
417220835Sglebius	r->proto = StrToProto(**av);
418220835Sglebius	protoName = **av;
419220835Sglebius	(*av)++; (*ac)--;
420187770Sluigi
421187770Sluigi	/*
422187770Sluigi	 * Extract local address.
423187770Sluigi	 */
424240351Skevlo	if (strchr(**av, ',') != NULL) {
425187770Sluigi		r->laddr.s_addr = INADDR_NONE;
426187770Sluigi		r->lport = ~0;
427187770Sluigi		numLocalPorts = 1;
428220835Sglebius		lsnat = **av;
429187770Sluigi	} else {
430188294Spiso		/*
431220802Sglebius		 * The sctp nat does not allow the port numbers to be mapped to
432220802Sglebius		 * new port numbers. Therefore, no ports are to be specified
433188294Spiso		 * in the target port field.
434188294Spiso		 */
435188294Spiso		if (r->proto == IPPROTO_SCTP) {
436220835Sglebius			if (strchr(**av, ':'))
437188294Spiso				errx(EX_DATAERR, "redirect_port:"
438220835Sglebius				    "port numbers do not change in sctp, so do "
439220835Sglebius				    "not specify them as part of the target");
440188294Spiso			else
441220835Sglebius				StrToAddr(**av, &r->laddr);
442188294Spiso		} else {
443220835Sglebius			if (StrToAddrAndPortRange(**av, &r->laddr, protoName,
444220835Sglebius			    &portRange) != 0)
445220835Sglebius				errx(EX_DATAERR, "redirect_port: "
446188294Spiso				    "invalid local port range");
447187770Sluigi
448188294Spiso			r->lport = GETLOPORT(portRange);
449188294Spiso			numLocalPorts = GETNUMPORTS(portRange);
450188294Spiso		}
451187770Sluigi	}
452220835Sglebius	(*av)++; (*ac)--;
453187770Sluigi
454187770Sluigi	/*
455187770Sluigi	 * Extract public port and optionally address.
456187770Sluigi	 */
457240351Skevlo	if (strchr(**av, ':') != NULL) {
458220835Sglebius		if (StrToAddrAndPortRange(**av, &r->paddr, protoName,
459187770Sluigi		    &portRange) != 0)
460220835Sglebius			errx(EX_DATAERR, "redirect_port: "
461187770Sluigi			    "invalid public port range");
462187770Sluigi	} else {
463187770Sluigi		r->paddr.s_addr = INADDR_ANY;
464220835Sglebius		if (StrToPortRange(**av, protoName, &portRange) != 0)
465220835Sglebius			errx(EX_DATAERR, "redirect_port: "
466187770Sluigi			    "invalid public port range");
467187770Sluigi	}
468187770Sluigi
469187770Sluigi	r->pport = GETLOPORT(portRange);
470188294Spiso	if (r->proto == IPPROTO_SCTP) { /* so the logic below still works */
471188294Spiso		numLocalPorts = GETNUMPORTS(portRange);
472188294Spiso		r->lport = r->pport;
473188294Spiso	}
474187770Sluigi	r->pport_cnt = GETNUMPORTS(portRange);
475220835Sglebius	(*av)++; (*ac)--;
476187770Sluigi
477187770Sluigi	/*
478187770Sluigi	 * Extract remote address and optionally port.
479220804Sglebius	 */
480220802Sglebius	/*
481223185Sglebius	 * NB: isdigit(**av) => we've to check that next parameter is really an
482187770Sluigi	 * option for this redirect entry, else stop here processing arg[cv].
483187770Sluigi	 */
484223185Sglebius	if (*ac != 0 && isdigit(***av)) {
485240351Skevlo		if (strchr(**av, ':') != NULL) {
486220835Sglebius			if (StrToAddrAndPortRange(**av, &r->raddr, protoName,
487187770Sluigi			    &portRange) != 0)
488220835Sglebius				errx(EX_DATAERR, "redirect_port: "
489187770Sluigi				    "invalid remote port range");
490187770Sluigi		} else {
491220802Sglebius			SETLOPORT(portRange, 0);
492187770Sluigi			SETNUMPORTS(portRange, 1);
493220835Sglebius			StrToAddr(**av, &r->raddr);
494187770Sluigi		}
495220835Sglebius		(*av)++; (*ac)--;
496187770Sluigi	} else {
497187770Sluigi		SETLOPORT(portRange, 0);
498187770Sluigi		SETNUMPORTS(portRange, 1);
499187770Sluigi		r->raddr.s_addr = INADDR_ANY;
500187770Sluigi	}
501187770Sluigi	r->rport = GETLOPORT(portRange);
502187770Sluigi	r->rport_cnt = GETNUMPORTS(portRange);
503187770Sluigi
504220802Sglebius	/*
505187770Sluigi	 * Make sure port ranges match up, then add the redirect ports.
506187770Sluigi	 */
507187770Sluigi	if (numLocalPorts != r->pport_cnt)
508220835Sglebius		errx(EX_DATAERR, "redirect_port: "
509187770Sluigi		    "port ranges must be equal in size");
510187770Sluigi
511187770Sluigi	/* Remote port range is allowed to be '0' which means all ports. */
512220802Sglebius	if (r->rport_cnt != numLocalPorts &&
513187770Sluigi	    (r->rport_cnt != 1 || r->rport != 0))
514220802Sglebius		errx(EX_DATAERR, "redirect_port: remote port must"
515187770Sluigi		    "be 0 or equal to local port range in size");
516187770Sluigi
517220835Sglebius	/* Setup LSNAT server pool. */
518220835Sglebius	if (lsnat != NULL) {
519220835Sglebius		struct cfg_spool *spool;
520220835Sglebius
521220835Sglebius		sep = strtok(lsnat, ",");
522187770Sluigi		while (sep != NULL) {
523220835Sglebius			spool = (struct cfg_spool *)buf;
524220835Sglebius			space += sizeof(struct cfg_spool);
525188294Spiso			/*
526220835Sglebius			 * The sctp nat does not allow the port numbers to
527220835Sglebius			 * be mapped to new port numbers. Therefore, no ports
528220835Sglebius			 * are to be specified in the target port field.
529188294Spiso			 */
530188294Spiso			if (r->proto == IPPROTO_SCTP) {
531188294Spiso				if (strchr (sep, ':')) {
532188294Spiso					errx(EX_DATAERR, "redirect_port:"
533188294Spiso					    "port numbers do not change in "
534188294Spiso					    "sctp, so do not specify them as "
535188294Spiso					    "part of the target");
536188294Spiso				} else {
537220835Sglebius					StrToAddr(sep, &spool->addr);
538220835Sglebius					spool->port = r->pport;
539188294Spiso				}
540188294Spiso			} else {
541220835Sglebius				if (StrToAddrAndPortRange(sep, &spool->addr,
542188294Spiso					protoName, &portRange) != 0)
543188294Spiso					errx(EX_DATAERR, "redirect_port:"
544188294Spiso					    "invalid local port range");
545188294Spiso				if (GETNUMPORTS(portRange) != 1)
546188294Spiso					errx(EX_DATAERR, "redirect_port: "
547188294Spiso					    "local port must be single in "
548188294Spiso					    "this context");
549220835Sglebius				spool->port = GETLOPORT(portRange);
550188294Spiso			}
551220804Sglebius			r->spool_cnt++;
552187770Sluigi			/* Point to the next possible cfg_spool. */
553220835Sglebius			buf = &buf[sizeof(struct cfg_spool)];
554187770Sluigi			sep = strtok(NULL, ",");
555187770Sluigi		}
556187770Sluigi	}
557220835Sglebius
558187770Sluigi	return (space);
559187770Sluigi}
560187770Sluigi
561187770Sluigistatic int
562220835Sglebiussetup_redir_proto(char *buf, int *ac, char ***av)
563187770Sluigi{
564220835Sglebius	struct cfg_redir *r;
565187770Sluigi	struct protoent *protoent;
566220835Sglebius	size_t space;
567220804Sglebius
568220835Sglebius	r = (struct cfg_redir *)buf;
569187770Sluigi	r->mode = REDIR_PROTO;
570220835Sglebius	/* Skip cfg_redir at beginning of buf. */
571220835Sglebius	buf = &buf[sizeof(struct cfg_redir)];
572220835Sglebius	space = sizeof(struct cfg_redir);
573220835Sglebius
574187770Sluigi	/*
575187770Sluigi	 * Extract protocol.
576220804Sglebius	 */
577220835Sglebius	protoent = getprotobyname(**av);
578187770Sluigi	if (protoent == NULL)
579220835Sglebius		errx(EX_DATAERR, "redirect_proto: unknown protocol %s", **av);
580187770Sluigi	else
581187770Sluigi		r->proto = protoent->p_proto;
582187770Sluigi
583220835Sglebius	(*av)++; (*ac)--;
584220804Sglebius
585187770Sluigi	/*
586187770Sluigi	 * Extract local address.
587187770Sluigi	 */
588220835Sglebius	StrToAddr(**av, &r->laddr);
589187770Sluigi
590220835Sglebius	(*av)++; (*ac)--;
591220804Sglebius
592187770Sluigi	/*
593187770Sluigi	 * Extract optional public address.
594187770Sluigi	 */
595220835Sglebius	if (*ac == 0) {
596220804Sglebius		r->paddr.s_addr = INADDR_ANY;
597220804Sglebius		r->raddr.s_addr = INADDR_ANY;
598187770Sluigi	} else {
599187770Sluigi		/* see above in setup_redir_port() */
600223185Sglebius		if (isdigit(***av)) {
601220835Sglebius			StrToAddr(**av, &r->paddr);
602220835Sglebius			(*av)++; (*ac)--;
603220804Sglebius
604187770Sluigi			/*
605187770Sluigi			 * Extract optional remote address.
606220804Sglebius			 */
607187770Sluigi			/* see above in setup_redir_port() */
608223185Sglebius			if (*ac != 0 && isdigit(***av)) {
609220835Sglebius				StrToAddr(**av, &r->raddr);
610220835Sglebius				(*av)++; (*ac)--;
611187770Sluigi			}
612220804Sglebius		}
613187770Sluigi	}
614220835Sglebius
615187770Sluigi	return (space);
616187770Sluigi}
617187770Sluigi
618187770Sluigistatic void
619187770Sluigiprint_nat_config(unsigned char *buf)
620187770Sluigi{
621187770Sluigi	struct cfg_nat *n;
622187770Sluigi	int i, cnt, flag, off;
623187770Sluigi	struct cfg_redir *t;
624187770Sluigi	struct cfg_spool *s;
625187770Sluigi	struct protoent *p;
626187770Sluigi
627187770Sluigi	n = (struct cfg_nat *)buf;
628187770Sluigi	flag = 1;
629187770Sluigi	off  = sizeof(*n);
630187770Sluigi	printf("ipfw nat %u config", n->id);
631187770Sluigi	if (strlen(n->if_name) != 0)
632187770Sluigi		printf(" if %s", n->if_name);
633187770Sluigi	else if (n->ip.s_addr != 0)
634187770Sluigi		printf(" ip %s", inet_ntoa(n->ip));
635187770Sluigi	while (n->mode != 0) {
636187770Sluigi		if (n->mode & PKT_ALIAS_LOG) {
637187770Sluigi			printf(" log");
638187770Sluigi			n->mode &= ~PKT_ALIAS_LOG;
639187770Sluigi		} else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
640187770Sluigi			printf(" deny_in");
641187770Sluigi			n->mode &= ~PKT_ALIAS_DENY_INCOMING;
642187770Sluigi		} else if (n->mode & PKT_ALIAS_SAME_PORTS) {
643187770Sluigi			printf(" same_ports");
644187770Sluigi			n->mode &= ~PKT_ALIAS_SAME_PORTS;
645223080Sae		} else if (n->mode & PKT_ALIAS_SKIP_GLOBAL) {
646223080Sae			printf(" skip_global");
647223080Sae			n->mode &= ~PKT_ALIAS_SKIP_GLOBAL;
648187770Sluigi		} else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
649187770Sluigi			printf(" unreg_only");
650187770Sluigi			n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
651187770Sluigi		} else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
652187770Sluigi			printf(" reset");
653187770Sluigi			n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
654187770Sluigi		} else if (n->mode & PKT_ALIAS_REVERSE) {
655187770Sluigi			printf(" reverse");
656187770Sluigi			n->mode &= ~PKT_ALIAS_REVERSE;
657187770Sluigi		} else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
658187770Sluigi			printf(" proxy_only");
659187770Sluigi			n->mode &= ~PKT_ALIAS_PROXY_ONLY;
660187770Sluigi		}
661187770Sluigi	}
662187770Sluigi	/* Print all the redirect's data configuration. */
663187770Sluigi	for (cnt = 0; cnt < n->redir_cnt; cnt++) {
664187770Sluigi		t = (struct cfg_redir *)&buf[off];
665187770Sluigi		off += SOF_REDIR;
666187770Sluigi		switch (t->mode) {
667187770Sluigi		case REDIR_ADDR:
668187770Sluigi			printf(" redirect_addr");
669187770Sluigi			if (t->spool_cnt == 0)
670187770Sluigi				printf(" %s", inet_ntoa(t->laddr));
671187770Sluigi			else
672187770Sluigi				for (i = 0; i < t->spool_cnt; i++) {
673187770Sluigi					s = (struct cfg_spool *)&buf[off];
674187770Sluigi					if (i)
675187770Sluigi						printf(",");
676220802Sglebius					else
677187770Sluigi						printf(" ");
678187770Sluigi					printf("%s", inet_ntoa(s->addr));
679187770Sluigi					off += SOF_SPOOL;
680187770Sluigi				}
681187770Sluigi			printf(" %s", inet_ntoa(t->paddr));
682187770Sluigi			break;
683187770Sluigi		case REDIR_PORT:
684187770Sluigi			p = getprotobynumber(t->proto);
685187770Sluigi			printf(" redirect_port %s ", p->p_name);
686187770Sluigi			if (!t->spool_cnt) {
687187770Sluigi				printf("%s:%u", inet_ntoa(t->laddr), t->lport);
688187770Sluigi				if (t->pport_cnt > 1)
689220802Sglebius					printf("-%u", t->lport +
690187770Sluigi					    t->pport_cnt - 1);
691187770Sluigi			} else
692187770Sluigi				for (i=0; i < t->spool_cnt; i++) {
693187770Sluigi					s = (struct cfg_spool *)&buf[off];
694187770Sluigi					if (i)
695187770Sluigi						printf(",");
696220802Sglebius					printf("%s:%u", inet_ntoa(s->addr),
697187770Sluigi					    s->port);
698187770Sluigi					off += SOF_SPOOL;
699187770Sluigi				}
700187770Sluigi
701187770Sluigi			printf(" ");
702187770Sluigi			if (t->paddr.s_addr)
703220802Sglebius				printf("%s:", inet_ntoa(t->paddr));
704187770Sluigi			printf("%u", t->pport);
705187770Sluigi			if (!t->spool_cnt && t->pport_cnt > 1)
706187770Sluigi				printf("-%u", t->pport + t->pport_cnt - 1);
707187770Sluigi
708187770Sluigi			if (t->raddr.s_addr) {
709187770Sluigi				printf(" %s", inet_ntoa(t->raddr));
710187770Sluigi				if (t->rport) {
711187770Sluigi					printf(":%u", t->rport);
712187770Sluigi					if (!t->spool_cnt && t->rport_cnt > 1)
713220802Sglebius						printf("-%u", t->rport +
714187770Sluigi						    t->rport_cnt - 1);
715187770Sluigi				}
716187770Sluigi			}
717187770Sluigi			break;
718187770Sluigi		case REDIR_PROTO:
719187770Sluigi			p = getprotobynumber(t->proto);
720220802Sglebius			printf(" redirect_proto %s %s", p->p_name,
721187770Sluigi			    inet_ntoa(t->laddr));
722187770Sluigi			if (t->paddr.s_addr != 0) {
723187770Sluigi				printf(" %s", inet_ntoa(t->paddr));
724187770Sluigi				if (t->raddr.s_addr)
725187770Sluigi					printf(" %s", inet_ntoa(t->raddr));
726187770Sluigi			}
727187770Sluigi			break;
728187770Sluigi		default:
729187770Sluigi			errx(EX_DATAERR, "unknown redir mode");
730187770Sluigi			break;
731187770Sluigi		}
732187770Sluigi	}
733187770Sluigi	printf("\n");
734187770Sluigi}
735187770Sluigi
736187770Sluigivoid
737187770Sluigiipfw_config_nat(int ac, char **av)
738187770Sluigi{
739220802Sglebius	struct cfg_nat *n;		/* Nat instance configuration. */
740220835Sglebius	int i, off, tok, ac1;
741223079Sae	char *id, *buf, **av1, *end;
742220835Sglebius	size_t len;
743220804Sglebius
744223499Sglebius	av++;
745223499Sglebius	ac--;
746187770Sluigi	/* Nat id. */
747223079Sae	if (ac == 0)
748187770Sluigi		errx(EX_DATAERR, "missing nat id");
749223079Sae	id = *av;
750223079Sae	i = (int)strtol(id, &end, 0);
751223079Sae	if (i <= 0 || *end != '\0')
752223079Sae		errx(EX_DATAERR, "illegal nat id: %s", id);
753223499Sglebius	av++;
754223499Sglebius	ac--;
755220802Sglebius	if (ac == 0)
756187770Sluigi		errx(EX_DATAERR, "missing option");
757187770Sluigi
758220835Sglebius	len = sizeof(struct cfg_nat);
759220835Sglebius	ac1 = ac;
760220835Sglebius	av1 = av;
761220835Sglebius	while (ac1 > 0) {
762220835Sglebius		tok = match_token(nat_params, *av1);
763223499Sglebius		ac1--;
764223499Sglebius		av1++;
765220835Sglebius		switch (tok) {
766220835Sglebius		case TOK_IP:
767220835Sglebius		case TOK_IF:
768223499Sglebius			ac1--;
769223499Sglebius			av1++;
770223080Sae			break;
771220835Sglebius		case TOK_ALOG:
772220835Sglebius		case TOK_DENY_INC:
773220835Sglebius		case TOK_SAME_PORTS:
774223080Sae		case TOK_SKIP_GLOBAL:
775220835Sglebius		case TOK_UNREG_ONLY:
776220835Sglebius		case TOK_RESET_ADDR:
777220835Sglebius		case TOK_ALIAS_REV:
778220835Sglebius		case TOK_PROXY_ONLY:
779220835Sglebius			break;
780220835Sglebius		case TOK_REDIR_ADDR:
781220835Sglebius			if (ac1 < 2)
782220835Sglebius				errx(EX_DATAERR, "redirect_addr: "
783220835Sglebius				    "not enough arguments");
784220835Sglebius			len += estimate_redir_addr(&ac1, &av1);
785223499Sglebius			av1 += 2;
786223499Sglebius			ac1 -= 2;
787220835Sglebius			break;
788220835Sglebius		case TOK_REDIR_PORT:
789220835Sglebius			if (ac1 < 3)
790220835Sglebius				errx(EX_DATAERR, "redirect_port: "
791220835Sglebius				    "not enough arguments");
792223499Sglebius			av1++;
793223499Sglebius			ac1--;
794220835Sglebius			len += estimate_redir_port(&ac1, &av1);
795223499Sglebius			av1 += 2;
796223499Sglebius			ac1 -= 2;
797223185Sglebius			/* Skip optional remoteIP/port */
798223416Sglebius			if (ac1 != 0 && isdigit(**av1)) {
799223499Sglebius				av1++;
800223499Sglebius				ac1--;
801223416Sglebius			}
802220835Sglebius			break;
803220835Sglebius		case TOK_REDIR_PROTO:
804220835Sglebius			if (ac1 < 2)
805220835Sglebius				errx(EX_DATAERR, "redirect_proto: "
806220835Sglebius				    "not enough arguments");
807220835Sglebius			len += sizeof(struct cfg_redir);
808223499Sglebius			av1 += 2;
809223499Sglebius			ac1 -= 2;
810223185Sglebius			/* Skip optional remoteIP/port */
811223416Sglebius			if (ac1 != 0 && isdigit(**av1)) {
812223499Sglebius				av1++;
813223499Sglebius				ac1--;
814223416Sglebius			}
815223416Sglebius			if (ac1 != 0 && isdigit(**av1)) {
816223499Sglebius				av1++;
817223499Sglebius				ac1--;
818223416Sglebius			}
819220835Sglebius			break;
820220835Sglebius		default:
821220835Sglebius			errx(EX_DATAERR, "unrecognised option ``%s''", av1[-1]);
822220835Sglebius		}
823220835Sglebius	}
824220835Sglebius
825220835Sglebius	if ((buf = malloc(len)) == NULL)
826220835Sglebius		errx(EX_OSERR, "malloc failed");
827220835Sglebius
828220835Sglebius	/* Offset in buf: save space for n at the beginning. */
829220835Sglebius	off = sizeof(*n);
830220835Sglebius	memset(buf, 0, len);
831220835Sglebius	n = (struct cfg_nat *)buf;
832220835Sglebius	n->id = i;
833220835Sglebius
834187770Sluigi	while (ac > 0) {
835187770Sluigi		tok = match_token(nat_params, *av);
836223499Sglebius		ac--;
837223499Sglebius		av++;
838187770Sluigi		switch (tok) {
839187770Sluigi		case TOK_IP:
840220802Sglebius			if (ac == 0)
841187770Sluigi				errx(EX_DATAERR, "missing option");
842187770Sluigi			if (!inet_aton(av[0], &(n->ip)))
843220802Sglebius				errx(EX_DATAERR, "bad ip address ``%s''",
844187770Sluigi				    av[0]);
845223499Sglebius			ac--;
846223499Sglebius			av++;
847220802Sglebius			break;
848187770Sluigi		case TOK_IF:
849220802Sglebius			if (ac == 0)
850187770Sluigi				errx(EX_DATAERR, "missing option");
851187770Sluigi			set_addr_dynamic(av[0], n);
852223499Sglebius			ac--;
853223499Sglebius			av++;
854187770Sluigi			break;
855187770Sluigi		case TOK_ALOG:
856187770Sluigi			n->mode |= PKT_ALIAS_LOG;
857187770Sluigi			break;
858187770Sluigi		case TOK_DENY_INC:
859187770Sluigi			n->mode |= PKT_ALIAS_DENY_INCOMING;
860187770Sluigi			break;
861187770Sluigi		case TOK_SAME_PORTS:
862187770Sluigi			n->mode |= PKT_ALIAS_SAME_PORTS;
863187770Sluigi			break;
864187770Sluigi		case TOK_UNREG_ONLY:
865187770Sluigi			n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
866187770Sluigi			break;
867223080Sae		case TOK_SKIP_GLOBAL:
868223080Sae			n->mode |= PKT_ALIAS_SKIP_GLOBAL;
869223080Sae			break;
870187770Sluigi		case TOK_RESET_ADDR:
871187770Sluigi			n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
872187770Sluigi			break;
873187770Sluigi		case TOK_ALIAS_REV:
874187770Sluigi			n->mode |= PKT_ALIAS_REVERSE;
875187770Sluigi			break;
876187770Sluigi		case TOK_PROXY_ONLY:
877187770Sluigi			n->mode |= PKT_ALIAS_PROXY_ONLY;
878187770Sluigi			break;
879220802Sglebius			/*
880220802Sglebius			 * All the setup_redir_* functions work directly in
881220802Sglebius			 * the final buffer, see above for details.
882187770Sluigi			 */
883187770Sluigi		case TOK_REDIR_ADDR:
884187770Sluigi		case TOK_REDIR_PORT:
885187770Sluigi		case TOK_REDIR_PROTO:
886187770Sluigi			switch (tok) {
887187770Sluigi			case TOK_REDIR_ADDR:
888220835Sglebius				i = setup_redir_addr(&buf[off], &ac, &av);
889220802Sglebius				break;
890187770Sluigi			case TOK_REDIR_PORT:
891220835Sglebius				i = setup_redir_port(&buf[off], &ac, &av);
892220802Sglebius				break;
893187770Sluigi			case TOK_REDIR_PROTO:
894220835Sglebius				i = setup_redir_proto(&buf[off], &ac, &av);
895187770Sluigi				break;
896187770Sluigi			}
897187770Sluigi			n->redir_cnt++;
898187770Sluigi			off += i;
899187770Sluigi			break;
900187770Sluigi		}
901187770Sluigi	}
902187770Sluigi
903187770Sluigi	i = do_cmd(IP_FW_NAT_CFG, buf, off);
904187770Sluigi	if (i)
905187770Sluigi		err(1, "setsockopt(%s)", "IP_FW_NAT_CFG");
906187770Sluigi
907187770Sluigi	if (!co.do_quiet) {
908187770Sluigi		/* After every modification, we show the resultant rule. */
909187770Sluigi		int _ac = 3;
910189395Sluigi		const char *_av[] = {"show", "config", id};
911189395Sluigi		ipfw_show_nat(_ac, (char **)(void *)_av);
912187770Sluigi	}
913187770Sluigi}
914187770Sluigi
915187770Sluigi
916187770Sluigivoid
917187770Sluigiipfw_show_nat(int ac, char **av)
918187770Sluigi{
919187770Sluigi	struct cfg_nat *n;
920187770Sluigi	struct cfg_redir *e;
921187770Sluigi	int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size;
922187770Sluigi	int nat_cnt, redir_cnt, r;
923187770Sluigi	uint8_t *data, *p;
924187770Sluigi	char *endptr;
925187770Sluigi
926187770Sluigi	do_rule = 0;
927187770Sluigi	nalloc = 1024;
928187770Sluigi	size = 0;
929187770Sluigi	data = NULL;
930187770Sluigi	frule = 0;
931187770Sluigi	lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */
932223499Sglebius	ac--;
933223499Sglebius	av++;
934187770Sluigi
935187770Sluigi	if (co.test_only)
936187770Sluigi		return;
937187770Sluigi
938187770Sluigi	/* Parse parameters. */
939187770Sluigi	for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) {
940187770Sluigi		if (!strncmp(av[0], "config", strlen(av[0]))) {
941220802Sglebius			cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1;
942187770Sluigi			continue;
943187770Sluigi		}
944187770Sluigi		/* Convert command line rule #. */
945187770Sluigi		frule = lrule = strtoul(av[0], &endptr, 10);
946187770Sluigi		if (*endptr == '-')
947187770Sluigi			lrule = strtoul(endptr+1, &endptr, 10);
948220804Sglebius		if (lrule == 0)
949187770Sluigi			err(EX_USAGE, "invalid rule number: %s", av[0]);
950187770Sluigi		do_rule = 1;
951187770Sluigi	}
952187770Sluigi
953187770Sluigi	nbytes = nalloc;
954187770Sluigi	while (nbytes >= nalloc) {
955187770Sluigi		nalloc = nalloc * 2;
956187770Sluigi		nbytes = nalloc;
957187770Sluigi		data = safe_realloc(data, nbytes);
958187770Sluigi		if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0)
959187770Sluigi			err(EX_OSERR, "getsockopt(IP_FW_GET_%s)",
960187770Sluigi			    (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG");
961187770Sluigi	}
962187770Sluigi	if (nbytes == 0)
963187770Sluigi		exit(0);
964187770Sluigi	if (do_cfg) {
965187770Sluigi		nat_cnt = *((int *)data);
966187770Sluigi		for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
967187770Sluigi			n = (struct cfg_nat *)&data[i];
968187770Sluigi			if (frule <= n->id && lrule >= n->id)
969187770Sluigi				print_nat_config(&data[i]);
970187770Sluigi			i += sizeof(struct cfg_nat);
971187770Sluigi			for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
972187770Sluigi				e = (struct cfg_redir *)&data[i];
973220802Sglebius				i += sizeof(struct cfg_redir) + e->spool_cnt *
974187770Sluigi				    sizeof(struct cfg_spool);
975187770Sluigi			}
976187770Sluigi		}
977187770Sluigi	} else {
978187770Sluigi		for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) {
979187770Sluigi			p = &data[i];
980187770Sluigi			if (p == data + nbytes)
981187770Sluigi				break;
982187770Sluigi			bcopy(p, &r, sizeof(int));
983187770Sluigi			if (do_rule) {
984187770Sluigi				if (!(frule <= r && lrule >= r))
985187770Sluigi					continue;
986187770Sluigi			}
987187770Sluigi			printf("nat %u: %s\n", r, p+sizeof(int));
988187770Sluigi		}
989187770Sluigi	}
990187770Sluigi}
991