Home | History | Annotate | Line # | Download | only in tools
      1 /*	$NetBSD: ipnat_y.y,v 1.4 2014/06/29 08:58:01 darrenr Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2012 by Darren Reed.
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  */
      8 %{
      9 #ifdef  __FreeBSD__
     10 # ifndef __FreeBSD_cc_version
     11 #  include <osreldate.h>
     12 # else
     13 #  if __FreeBSD_cc_version < 430000
     14 #   include <osreldate.h>
     15 #  endif
     16 # endif
     17 #endif
     18 #include <stdio.h>
     19 #include <unistd.h>
     20 #include <string.h>
     21 #include <fcntl.h>
     22 #include <errno.h>
     23 #if !defined(__SVR4) && !defined(__GNUC__)
     24 #include <strings.h>
     25 #endif
     26 #include <sys/types.h>
     27 #include <sys/param.h>
     28 #include <sys/file.h>
     29 #include <stdlib.h>
     30 #include <stddef.h>
     31 #include <sys/socket.h>
     32 #include <sys/ioctl.h>
     33 #include <netinet/in.h>
     34 #include <netinet/in_systm.h>
     35 #include <sys/time.h>
     36 #include <syslog.h>
     37 #include <net/if.h>
     38 #if __FreeBSD_version >= 300000
     39 # include <net/if_var.h>
     40 #endif
     41 #include <netdb.h>
     42 #include <arpa/nameser.h>
     43 #include <resolv.h>
     44 #include "ipf.h"
     45 #include "netinet/ipl.h"
     46 #include "ipnat_l.h"
     47 
     48 #define	YYDEBUG	1
     49 
     50 extern	void	yyerror __P((char *));
     51 extern	int	yyparse __P((void));
     52 extern	int	yylex __P((void));
     53 extern	int	yydebug;
     54 extern	FILE	*yyin;
     55 extern	int	yylineNum;
     56 
     57 static	ipnat_t		*nattop = NULL;
     58 static	ipnat_t		*nat = NULL;
     59 static	int		natfd = -1;
     60 static	ioctlfunc_t	natioctlfunc = NULL;
     61 static	addfunc_t	nataddfunc = NULL;
     62 static	int		suggest_port = 0;
     63 static	proxyrule_t	*prules = NULL;
     64 static	int		parser_error = 0;
     65 
     66 static	void	newnatrule __P((void));
     67 static	void	setnatproto __P((int));
     68 static	void	setmapifnames __P((void));
     69 static	void	setrdrifnames __P((void));
     70 static	void	proxy_setconfig __P((int));
     71 static	void	proxy_unsetconfig __P((void));
     72 static	namelist_t *proxy_dns_add_pass __P((char *, char *));
     73 static	namelist_t *proxy_dns_add_block __P((char *, char *));
     74 static	void	proxy_addconfig __P((char *, int, char *, namelist_t *));
     75 static	void	proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
     76 				      char *, namelist_t *));
     77 static	void	proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
     78 static	void	setmapifnames __P((void));
     79 static	void	setrdrifnames __P((void));
     80 static	void	setifname __P((ipnat_t **, int, char *));
     81 static	int	addname __P((ipnat_t **, char *));
     82 %}
     83 %union	{
     84 	char	*str;
     85 	u_32_t	num;
     86 	struct {
     87 		i6addr_t	a;
     88 		int		f;
     89 	} ipa;
     90 	frentry_t	fr;
     91 	frtuc_t	*frt;
     92 	u_short	port;
     93 	struct	{
     94 		int	p1;
     95 		int	p2;
     96 		int	pc;
     97 	} pc;
     98 	struct	{
     99 		i6addr_t	a;
    100 		i6addr_t	m;
    101 		int	t;		/* Address type */
    102 		int	u;
    103 		int	f;		/* Family */
    104 		int	v;		/* IP version */
    105 		int	s;		/* 0 = number, 1 = text */
    106 		int	n;		/* number */
    107 	} ipp;
    108 	union	i6addr	ip6;
    109 	namelist_t	*names;
    110 };
    111 
    112 %token  <num>   YY_NUMBER YY_HEX
    113 %token  <str>   YY_STR
    114 %token	  YY_COMMENT
    115 %token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
    116 %token	  YY_RANGE_OUT YY_RANGE_IN
    117 %token  <ip6>   YY_IPV6
    118 
    119 %token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
    120 %token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
    121 %token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
    122 %token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
    123 %token	IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
    124 %token	IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
    125 %token	IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
    126 %token	IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
    127 %type	<port> portspec
    128 %type	<num> hexnumber compare range proto
    129 %type	<num> saddr daddr sobject dobject mapfrom rdrfrom dip
    130 %type	<ipa> hostname ipv4 ipaddr
    131 %type	<ipp> addr rhsaddr rhdaddr erhdaddr
    132 %type	<pc> portstuff portpair comaports srcports dstports
    133 %type	<names> dnslines dnsline
    134 %%
    135 file:	line
    136 	| assign
    137 	| file line
    138 	| file assign
    139 	| file pconf ';'
    140 	;
    141 
    142 line:	xx rule		{ int err;
    143 			  while ((nat = nattop) != NULL) {
    144 				if (nat->in_v[0] == 0)
    145 					nat->in_v[0] = 4;
    146 				if (nat->in_v[1] == 0)
    147 					nat->in_v[1] = nat->in_v[0];
    148 				nattop = nat->in_next;
    149 				err = (*nataddfunc)(natfd, natioctlfunc, nat);
    150 				free(nat);
    151 				if (err != 0) {
    152 					parser_error = err;
    153 					break;
    154 				}
    155 			  }
    156 			  if (parser_error == 0 && prules != NULL) {
    157 				proxy_loadrules(natfd, natioctlfunc, prules);
    158 				prules = NULL;
    159 			  }
    160 			  resetlexer();
    161 			}
    162 	| YY_COMMENT
    163 	;
    164 
    165 assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
    166 					  resetlexer();
    167 					  free($1);
    168 					  free($3);
    169 					  yyvarnext = 0;
    170 					}
    171 	;
    172 
    173 assigning:
    174 	'='				{ yyvarnext = 1; }
    175 	;
    176 
    177 xx:					{ newnatrule(); }
    178 	;
    179 
    180 rule:	map eol
    181 	| mapblock eol
    182 	| redir eol
    183 	| rewrite ';'
    184 	| divert ';'
    185 	;
    186 
    187 no:	IPNY_NO				{ nat->in_flags |= IPN_NO; }
    188 	;
    189 
    190 eol:	| ';'
    191 	;
    192 
    193 map:	mapit ifnames addr tlate rhsaddr proxy mapoptions
    194 				{ if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
    195 					yyerror("3.address family mismatch");
    196 				  if (nat->in_v[0] == 0 && $5.v != 0)
    197 					nat->in_v[0] = $5.v;
    198 				  else if (nat->in_v[0] == 0 && $3.v != 0)
    199 					nat->in_v[0] = $3.v;
    200 				  if (nat->in_v[1] == 0 && $5.v != 0)
    201 					nat->in_v[1] = $5.v;
    202 				  else if (nat->in_v[1] == 0 && $3.v != 0)
    203 					nat->in_v[1] = $3.v;
    204 				  nat->in_osrcatype = $3.t;
    205 				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
    206 					sizeof($3.a));
    207 				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
    208 					sizeof($3.a));
    209 				  nat->in_nsrcatype = $5.t;
    210 				  nat->in_nsrcafunc = $5.u;
    211 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
    212 					sizeof($5.a));
    213 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
    214 					sizeof($5.a));
    215 
    216 				  setmapifnames();
    217 				}
    218 	| mapit ifnames addr tlate rhsaddr mapport mapoptions
    219 				{ if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
    220 					yyerror("4.address family mismatch");
    221 				  if (nat->in_v[1] == 0 && $5.v != 0)
    222 					nat->in_v[1] = $5.v;
    223 				  else if (nat->in_v[0] == 0 && $3.v != 0)
    224 					nat->in_v[0] = $3.v;
    225 				  if (nat->in_v[0] == 0 && $5.v != 0)
    226 					nat->in_v[0] = $5.v;
    227 				  else if (nat->in_v[1] == 0 && $3.v != 0)
    228 					nat->in_v[1] = $3.v;
    229 				  nat->in_osrcatype = $3.t;
    230 				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
    231 					sizeof($3.a));
    232 				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
    233 					sizeof($3.a));
    234 				  nat->in_nsrcatype = $5.t;
    235 				  nat->in_nsrcafunc = $5.u;
    236 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
    237 					sizeof($5.a));
    238 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
    239 					sizeof($5.a));
    240 
    241 				  setmapifnames();
    242 				}
    243 	| no mapit ifnames addr setproto ';'
    244 				{ if (nat->in_v[0] == 0)
    245 					nat->in_v[0] = $4.v;
    246 				  nat->in_osrcatype = $4.t;
    247 				  bcopy(&$4.a, &nat->in_osrc.na_addr[0],
    248 					sizeof($4.a));
    249 				  bcopy(&$4.m, &nat->in_osrc.na_addr[1],
    250 					sizeof($4.a));
    251 
    252 				  setmapifnames();
    253 				}
    254 	| mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
    255 				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
    256 					yyerror("5.address family mismatch");
    257 				  if (nat->in_v[0] == 0 && $5.v != 0)
    258 					nat->in_v[0] = $5.v;
    259 				  else if (nat->in_v[0] == 0 && $3 != 0)
    260 					nat->in_v[0] = ftov($3);
    261 				  if (nat->in_v[1] == 0 && $5.v != 0)
    262 					nat->in_v[1] = $5.v;
    263 				  else if (nat->in_v[1] == 0 && $3 != 0)
    264 					nat->in_v[1] = ftov($3);
    265 				  nat->in_nsrcatype = $5.t;
    266 				  nat->in_nsrcafunc = $5.u;
    267 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
    268 					sizeof($5.a));
    269 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
    270 					sizeof($5.a));
    271 
    272 				  setmapifnames();
    273 				}
    274 	| no mapit ifnames mapfrom setproto ';'
    275 				{ nat->in_v[0] = ftov($4);
    276 				  setmapifnames();
    277 				}
    278 	| mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
    279 				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
    280 					yyerror("6.address family mismatch");
    281 				  if (nat->in_v[0] == 0 && $5.v != 0)
    282 					nat->in_v[0] = $5.v;
    283 				  else if (nat->in_v[0] == 0 && $3 != 0)
    284 					nat->in_v[0] = ftov($3);
    285 				  if (nat->in_v[1] == 0 && $5.v != 0)
    286 					nat->in_v[1] = $5.v;
    287 				  else if (nat->in_v[1] == 0 && $3 != 0)
    288 					nat->in_v[1] = ftov($3);
    289 				  nat->in_nsrcatype = $5.t;
    290 				  nat->in_nsrcafunc = $5.u;
    291 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
    292 					sizeof($5.a));
    293 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
    294 					sizeof($5.a));
    295 
    296 				  setmapifnames();
    297 				}
    298 	;
    299 
    300 mapblock:
    301 	mapblockit ifnames addr tlate addr ports mapoptions
    302 				{ if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
    303 					yyerror("7.address family mismatch");
    304 				  if (nat->in_v[0] == 0 && $5.v != 0)
    305 					nat->in_v[0] = $5.v;
    306 				  else if (nat->in_v[0] == 0 && $3.v != 0)
    307 					nat->in_v[0] = $3.v;
    308 				  if (nat->in_v[1] == 0 && $5.v != 0)
    309 					nat->in_v[1] = $5.v;
    310 				  else if (nat->in_v[1] == 0 && $3.v != 0)
    311 					nat->in_v[1] = $3.v;
    312 				  nat->in_osrcatype = $3.t;
    313 				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
    314 					sizeof($3.a));
    315 				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
    316 					sizeof($3.a));
    317 				  nat->in_nsrcatype = $5.t;
    318 				  nat->in_nsrcafunc = $5.u;
    319 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
    320 					sizeof($5.a));
    321 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
    322 					sizeof($5.a));
    323 
    324 				  setmapifnames();
    325 				}
    326 	| no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
    327 				{ if (nat->in_v[0] == 0)
    328 					nat->in_v[0] = $5.v;
    329 				  if (nat->in_v[1] == 0)
    330 					nat->in_v[1] = $5.v;
    331 				  nat->in_osrcatype = $5.t;
    332 				  bcopy(&$5.a, &nat->in_osrc.na_addr[0],
    333 					sizeof($5.a));
    334 				  bcopy(&$5.m, &nat->in_osrc.na_addr[1],
    335 					sizeof($5.a));
    336 
    337 				  setmapifnames();
    338 				}
    339 	;
    340 
    341 redir:	rdrit ifnames addr dport tlate dip nport setproto rdroptions
    342 				{ if ($6 != 0 && $3.f != 0 && $6 != $3.f)
    343 					yyerror("21.address family mismatch");
    344 				  if (nat->in_v[0] == 0) {
    345 					if ($3.v != AF_UNSPEC)
    346 						nat->in_v[0] = ftov($3.f);
    347 					  else
    348 						nat->in_v[0] = ftov($6);
    349 				  }
    350 				  nat->in_odstatype = $3.t;
    351 				  bcopy(&$3.a, &nat->in_odst.na_addr[0],
    352 					sizeof($3.a));
    353 				  bcopy(&$3.m, &nat->in_odst.na_addr[1],
    354 					sizeof($3.a));
    355 
    356 				  setrdrifnames();
    357 				}
    358 	| no rdrit ifnames addr dport setproto ';'
    359 				{ if (nat->in_v[0] == 0)
    360 					nat->in_v[0] = ftov($4.f);
    361 				  nat->in_odstatype = $4.t;
    362 				  bcopy(&$4.a, &nat->in_odst.na_addr[0],
    363 					sizeof($4.a));
    364 				  bcopy(&$4.m, &nat->in_odst.na_addr[1],
    365 					sizeof($4.a));
    366 
    367 				  setrdrifnames();
    368 				}
    369 	| rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
    370 				{ if ($5 != 0 && $3 != 0 && $5 != $3)
    371 					yyerror("20.address family mismatch");
    372 				  if (nat->in_v[0] == 0) {
    373 					  if ($3 != AF_UNSPEC)
    374 						nat->in_v[0] = ftov($3);
    375 					  else
    376 						nat->in_v[0] = ftov($5);
    377 				  }
    378 				  setrdrifnames();
    379 				}
    380 	| no rdrit ifnames rdrfrom setproto ';'
    381 				{ nat->in_v[0] = ftov($4);
    382 
    383 				  setrdrifnames();
    384 				}
    385 	;
    386 
    387 rewrite:
    388 	IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
    389 				{ if (nat->in_v[0] == 0)
    390 					nat->in_v[0] = ftov($4);
    391 				  if (nat->in_redir & NAT_MAP)
    392 					setmapifnames();
    393 				  else
    394 					setrdrifnames();
    395 				  nat->in_redir |= NAT_REWRITE;
    396 				}
    397 	;
    398 
    399 divert:	IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
    400 				{ if (nat->in_v[0] == 0)
    401 					nat->in_v[0] = ftov($4);
    402 				  if (nat->in_redir & NAT_MAP) {
    403 					setmapifnames();
    404 					nat->in_pr[0] = IPPROTO_UDP;
    405 				  } else {
    406 					setrdrifnames();
    407 					nat->in_pr[1] = IPPROTO_UDP;
    408 				  }
    409 				  nat->in_flags &= ~IPN_TCP;
    410 				}
    411 	;
    412 
    413 tlate:	IPNY_TLATE		{ yyexpectaddr = 1; }
    414 	;
    415 
    416 pconf:	IPNY_PROXY		{ yysetdict(proxies); }
    417 	IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
    418 				{ proxy_setconfig(IPNY_DNS); }
    419 	dnslines ';' '}'
    420 				{ proxy_addconfig("dns", $5, $7, $10);
    421 				  proxy_unsetconfig();
    422 				}
    423 	;
    424 
    425 dnslines:
    426 	dnsline 		{ $$ = $1; }
    427 	| dnslines ';' dnsline	{ $$ = $1; $1->na_next = $3; }
    428 	;
    429 
    430 dnsline:
    431 	IPNY_ALLOW YY_STR	{ $$ = proxy_dns_add_pass(NULL, $2); }
    432 	| IPNY_DENY YY_STR	{ $$ = proxy_dns_add_block(NULL, $2); }
    433 	| IPNY_ALLOW '.' YY_STR	{ $$ = proxy_dns_add_pass(".", $3); }
    434 	| IPNY_DENY '.' YY_STR	{ $$ = proxy_dns_add_block(".", $3); }
    435 	;
    436 
    437 oninout:
    438 	inout IPNY_ON ifnames	{ ; }
    439 	;
    440 
    441 inout:	IPNY_IN			{ nat->in_redir = NAT_REDIRECT; }
    442 	| IPNY_OUT		{ nat->in_redir = NAT_MAP; }
    443 	;
    444 
    445 rwrproto:
    446 	| IPNY_PROTO setproto
    447 	;
    448 
    449 newdst:	src rhsaddr srcports dst erhdaddr dstports
    450 				{ nat->in_nsrc.na_addr[0] = $2.a;
    451 				  nat->in_nsrc.na_addr[1] = $2.m;
    452 				  nat->in_nsrc.na_atype = $2.t;
    453 				  if ($2.t == FRI_LOOKUP) {
    454 					nat->in_nsrc.na_type = $2.u;
    455 					nat->in_nsrc.na_subtype = $2.s;
    456 					nat->in_nsrc.na_num = $2.n;
    457 				  }
    458 				  nat->in_nsports[0] = $3.p1;
    459 				  nat->in_nsports[1] = $3.p2;
    460 				  nat->in_ndst.na_addr[0] = $5.a;
    461 				  nat->in_ndst.na_addr[1] = $5.m;
    462 				  nat->in_ndst.na_atype = $5.t;
    463 				  if ($5.t == FRI_LOOKUP) {
    464 					nat->in_ndst.na_type = $5.u;
    465 					nat->in_ndst.na_subtype = $5.s;
    466 					nat->in_ndst.na_num = $5.n;
    467 				  }
    468 				  nat->in_ndports[0] = $6.p1;
    469 				  nat->in_ndports[1] = $6.p2;
    470 				}
    471 	;
    472 
    473 divdst:	src addr ',' portspec dst addr ',' portspec IPNY_UDP
    474 				{ nat->in_nsrc.na_addr[0] = $2.a;
    475 				  if ($2.m.in4.s_addr != 0xffffffff)
    476 					yyerror("divert must have /32 dest");
    477 				  nat->in_nsrc.na_addr[1] = $2.m;
    478 				  nat->in_nsports[0] = $4;
    479 				  nat->in_nsports[1] = $4;
    480 
    481 				  nat->in_ndst.na_addr[0] = $6.a;
    482 				  nat->in_ndst.na_addr[1] = $6.m;
    483 				  if ($6.m.in4.s_addr != 0xffffffff)
    484 					yyerror("divert must have /32 dest");
    485 				  nat->in_ndports[0] = $8;
    486 				  nat->in_ndports[1] = $8;
    487 
    488 				  nat->in_redir |= NAT_DIVERTUDP;
    489 				}
    490 	;
    491 
    492 src:	IPNY_SRC		{ yyexpectaddr = 1; }
    493 	;
    494 
    495 dst:	IPNY_DST		{ yyexpectaddr = 1; }
    496 	;
    497 
    498 srcports:
    499 	comaports		{ $$.p1 = $1.p1;
    500 				  $$.p2 = $1.p2;
    501 				}
    502 	| IPNY_PORT '=' portspec
    503 				{ $$.p1 = $3;
    504 				  $$.p2 = $3;
    505 				  nat->in_flags |= IPN_FIXEDSPORT;
    506 				}
    507 	;
    508 
    509 dstports:
    510 	comaports		{ $$.p1 = $1.p1;
    511 				  $$.p2 = $1.p2;
    512 				}
    513 	| IPNY_PORT '=' portspec
    514 				{ $$.p1 = $3;
    515 				  $$.p2 = $3;
    516 				  nat->in_flags |= IPN_FIXEDDPORT;
    517 				}
    518 	;
    519 
    520 comaports:
    521 				{ $$.p1 = 0;
    522 				  $$.p2 = 0;
    523 				}
    524 	| ','			{ if (!(nat->in_flags & IPN_TCPUDP))
    525 					yyerror("must be TCP/UDP for ports");
    526 				}
    527 	portpair		{ $$.p1 = $3.p1;
    528 				  $$.p2 = $3.p2;
    529 				}
    530 	;
    531 
    532 proxy:	| IPNY_PROXY port portspec YY_STR '/' proto
    533 			{ int pos;
    534 			  pos = addname(&nat, $4);
    535 			  nat->in_plabel = pos;
    536 			  if (nat->in_dcmp == 0) {
    537 				nat->in_odport = $3;
    538 			  } else if ($3 != nat->in_odport) {
    539 				yyerror("proxy port numbers not consistant");
    540 			  }
    541 			  nat->in_ndport = $3;
    542 			  setnatproto($6);
    543 			  free($4);
    544 			}
    545 	| IPNY_PROXY port YY_STR YY_STR '/' proto
    546 			{ int pnum, pos;
    547 			  pos = addname(&nat, $4);
    548 			  nat->in_plabel = pos;
    549 			  pnum = getportproto($3, $6);
    550 			  if (pnum == -1)
    551 				yyerror("invalid port number");
    552 			  nat->in_odport = ntohs(pnum);
    553 			  nat->in_ndport = ntohs(pnum);
    554 			  setnatproto($6);
    555 			  free($3);
    556 			  free($4);
    557 			}
    558 	| IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
    559 			{ int pos;
    560 			  pos = addname(&nat, $4);
    561 			  nat->in_plabel = pos;
    562 			  if (nat->in_dcmp == 0) {
    563 				nat->in_odport = $3;
    564 			  } else if ($3 != nat->in_odport) {
    565 				yyerror("proxy port numbers not consistant");
    566 			  }
    567 			  nat->in_ndport = $3;
    568 			  setnatproto($6);
    569 			  nat->in_pconfig = addname(&nat, $8);
    570 			  free($4);
    571 			  free($8);
    572 			}
    573 	| IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
    574 			{ int pnum, pos;
    575 			  pos = addname(&nat, $4);
    576 			  nat->in_plabel = pos;
    577 			  pnum = getportproto($3, $6);
    578 			  if (pnum == -1)
    579 				yyerror("invalid port number");
    580 			  nat->in_odport = ntohs(pnum);
    581 			  nat->in_ndport = ntohs(pnum);
    582 			  setnatproto($6);
    583 			  pos = addname(&nat, $8);
    584 			  nat->in_pconfig = pos;
    585 			  free($3);
    586 			  free($4);
    587 			  free($8);
    588 			}
    589 	;
    590 setproto:
    591 	| proto				{ if (nat->in_pr[0] != 0 ||
    592 					      nat->in_pr[1] != 0 ||
    593 					      nat->in_flags & IPN_TCPUDP)
    594 						yyerror("protocol set twice");
    595 					  setnatproto($1);
    596 					}
    597 	| IPNY_TCPUDP			{ if (nat->in_pr[0] != 0 ||
    598 					      nat->in_pr[1] != 0 ||
    599 					      nat->in_flags & IPN_TCPUDP)
    600 						yyerror("protocol set twice");
    601 					  nat->in_flags |= IPN_TCPUDP;
    602 					  nat->in_pr[0] = 0;
    603 					  nat->in_pr[1] = 0;
    604 					}
    605 	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_pr[0] != 0 ||
    606 					      nat->in_pr[1] != 0 ||
    607 					      nat->in_flags & IPN_TCPUDP)
    608 						yyerror("protocol set twice");
    609 					  nat->in_flags |= IPN_TCPUDP;
    610 					  nat->in_pr[0] = 0;
    611 					  nat->in_pr[1] = 0;
    612 					}
    613 	;
    614 
    615 rhsaddr:
    616 	addr				{ $$ = $1;
    617 					  yyexpectaddr = 0;
    618 					}
    619 	| hostname '-' { yyexpectaddr = 1; } hostname
    620 					{ $$.t = FRI_RANGE;
    621 					  if ($1.f != $4.f)
    622 						yyerror("8.address family "
    623 							"mismatch");
    624 					  $$.f = $1.f;
    625 					  $$.v = ftov($1.f);
    626 					  $$.a = $1.a;
    627 					  $$.m = $4.a;
    628 					  nat->in_flags |= IPN_SIPRANGE;
    629 					  yyexpectaddr = 0;
    630 					}
    631 	| IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
    632 					{ $$.t = FRI_RANGE;
    633 					  if ($2.f != $5.f)
    634 						yyerror("9.address family "
    635 							"mismatch");
    636 					  $$.f = $2.f;
    637 					  $$.v = ftov($2.f);
    638 					  $$.a = $2.a;
    639 					  $$.m = $5.a;
    640 					  nat->in_flags |= IPN_SIPRANGE;
    641 					  yyexpectaddr = 0;
    642 					}
    643 	;
    644 
    645 dip:
    646 	hostname ',' { yyexpectaddr = 1; } hostname
    647 				{ nat->in_flags |= IPN_SPLIT;
    648 				  if ($1.f != $4.f)
    649 					yyerror("10.address family "
    650 						"mismatch");
    651 				  $$ = $1.f;
    652 				  nat->in_ndstip6 = $1.a;
    653 				  nat->in_ndstmsk6 = $4.a;
    654 				  nat->in_ndstatype = FRI_SPLIT;
    655 				  yyexpectaddr = 0;
    656 				}
    657 	| rhdaddr		{ int bits;
    658 				  nat->in_ndstip6 = $1.a;
    659 				  nat->in_ndstmsk6 = $1.m;
    660 				  nat->in_ndst.na_atype = $1.t;
    661 				  yyexpectaddr = 0;
    662 				  if ($1.f == AF_INET)
    663 					bits = count4bits($1.m.in4.s_addr);
    664 				  else
    665 					bits = count6bits($1.m.i6);
    666 				  if (($1.f == AF_INET) && (bits != 0) &&
    667 				      (bits != 32)) {
    668 					yyerror("dest ip bitmask not /32");
    669 				  } else if (($1.f == AF_INET6) &&
    670 					     (bits != 0) && (bits != 128)) {
    671 					yyerror("dest ip bitmask not /128");
    672 				  }
    673 				  $$ = $1.f;
    674 				}
    675 	;
    676 
    677 rhdaddr:
    678 	addr				{ $$ = $1;
    679 					  yyexpectaddr = 0;
    680 					}
    681 	| hostname '-' hostname		{ bzero(&$$, sizeof($$));
    682 					  $$.t = FRI_RANGE;
    683 					  if ($1.f != 0 && $3.f != 0 &&
    684 					      $1.f != $3.f)
    685 						yyerror("11.address family "
    686 							"mismatch");
    687 					  $$.a = $1.a;
    688 					  $$.m = $3.a;
    689 					  nat->in_flags |= IPN_DIPRANGE;
    690 					  yyexpectaddr = 0;
    691 					}
    692 	| IPNY_RANGE hostname '-' hostname
    693 					{ bzero(&$$, sizeof($$));
    694 					  $$.t = FRI_RANGE;
    695 					  if ($2.f != 0 && $4.f != 0 &&
    696 					      $2.f != $4.f)
    697 						yyerror("12.address family "
    698 							"mismatch");
    699 					  $$.a = $2.a;
    700 					  $$.m = $4.a;
    701 					  nat->in_flags |= IPN_DIPRANGE;
    702 					  yyexpectaddr = 0;
    703 					}
    704 	;
    705 
    706 erhdaddr:
    707 	rhdaddr				{ $$ = $1; }
    708 	| IPNY_DSTLIST '/' YY_NUMBER	{ $$.t = FRI_LOOKUP;
    709 					  $$.u = IPLT_DSTLIST;
    710 					  $$.s = 0;
    711 					  $$.n = $3;
    712 					}
    713 	| IPNY_DSTLIST '/' YY_STR	{ $$.t = FRI_LOOKUP;
    714 					  $$.u = IPLT_DSTLIST;
    715 					  $$.s = 1;
    716 					  $$.n = addname(&nat, $3);
    717 					}
    718 	;
    719 
    720 port:	IPNY_PORT			{ suggest_port = 1; }
    721 	;
    722 
    723 portspec:
    724 	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
    725 						yyerror("invalid port number");
    726 					  else
    727 						$$ = $1;
    728 					}
    729 	| YY_STR			{ if (getport(NULL, $1,
    730 						      &($$), NULL) == -1)
    731 						yyerror("invalid port number");
    732 					  $$ = ntohs($$);
    733 					}
    734 	;
    735 
    736 portpair:
    737 	portspec			{ $$.p1 = $1; $$.p2 = $1; }
    738 	| portspec '-' portspec		{ $$.p1 = $1; $$.p2 = $3; }
    739 	| portspec ':' portspec		{ $$.p1 = $1; $$.p2 = $3; }
    740 	;
    741 
    742 dport:	| port portpair			{ nat->in_odport = $2.p1;
    743 					  if ($2.p2 == 0)
    744 						nat->in_dtop = $2.p1;
    745 					  else
    746 						nat->in_dtop = $2.p2;
    747 					}
    748 	;
    749 
    750 nport:	| port portpair			{ nat->in_dpmin = $2.p1;
    751 					  nat->in_dpnext = $2.p1;
    752 					  nat->in_dpmax = $2.p2;
    753 					  nat->in_ndport = $2.p1;
    754 					  if (nat->in_dtop == 0)
    755 						nat->in_dtop = $2.p2;
    756 					}
    757 	| port '=' portspec		{ nat->in_dpmin = $3;
    758 					  nat->in_dpnext = $3;
    759 					  nat->in_ndport = $3;
    760 					  if (nat->in_dtop == 0)
    761 						nat->in_dtop = nat->in_odport;
    762 					  nat->in_flags |= IPN_FIXEDDPORT;
    763 					}
    764 	;
    765 
    766 ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_spmin = $2; }
    767 	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
    768 	;
    769 
    770 mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
    771 	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
    772 	;
    773 
    774 rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
    775 	;
    776 
    777 mapblockit:
    778 	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
    779 	;
    780 
    781 mapfrom:
    782 	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
    783 						yyerror("13.address family "
    784 							"mismatch");
    785 					  $$ = $2;
    786 					}
    787 	| from sobject '!' to dobject
    788 					{ if ($2 != 0 && $5 != 0 && $2 != $5)
    789 						yyerror("14.address family "
    790 							"mismatch");
    791 					  nat->in_flags |= IPN_NOTDST;
    792 					  $$ = $2;
    793 					}
    794 	| from sobject to '!' dobject
    795 					{ if ($2 != 0 && $5 != 0 && $2 != $5)
    796 						yyerror("15.address family "
    797 							"mismatch");
    798 					  nat->in_flags |= IPN_NOTDST;
    799 					  $$ = $2;
    800 					}
    801 	;
    802 
    803 rdrfrom:
    804 	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
    805 						yyerror("16.address family "
    806 							"mismatch");
    807 					  $$ = $2;
    808 					}
    809 	| '!' from sobject to dobject
    810 					{ if ($3 != 0 && $5 != 0 && $3 != $5)
    811 						yyerror("17.address family "
    812 							"mismatch");
    813 					  nat->in_flags |= IPN_NOTSRC;
    814 					  $$ = $3;
    815 					}
    816 	| from '!' sobject to dobject
    817 					{ if ($3 != 0 && $5 != 0 && $3 != $5)
    818 						yyerror("18.address family "
    819 							"mismatch");
    820 					  nat->in_flags |= IPN_NOTSRC;
    821 					  $$ = $3;
    822 					}
    823 	;
    824 
    825 from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER;
    826 					  yyexpectaddr = 1;
    827 					}
    828 	;
    829 
    830 to:	IPNY_TO				{ yyexpectaddr = 1; }
    831 	;
    832 
    833 ifnames:
    834 	ifname family			{ yyexpectaddr = 1; }
    835 	| ifname ',' otherifname family	{ yyexpectaddr = 1; }
    836 	;
    837 
    838 ifname:	YY_STR				{ setifname(&nat, 0, $1);
    839 					  free($1);
    840 					}
    841 	;
    842 
    843 family:	| IPNY_INET			{ nat->in_v[0] = 4; nat->in_v[1] = 4; }
    844 	| IPNY_INET6			{ nat->in_v[0] = 6; nat->in_v[1] = 6; }
    845 	;
    846 
    847 otherifname:
    848 	YY_STR				{ setifname(&nat, 1, $1);
    849 					  free($1);
    850 					}
    851 	;
    852 
    853 mapport:
    854 	IPNY_PORTMAP tcpudp portpair sequential
    855 					{ nat->in_spmin = $3.p1;
    856 					  nat->in_spmax = $3.p2;
    857 					}
    858 	| IPNY_PORTMAP portpair tcpudp sequential
    859 					{ nat->in_spmin = $2.p1;
    860 					  nat->in_spmax = $2.p2;
    861 					}
    862 	| IPNY_PORTMAP tcpudp IPNY_AUTO sequential
    863 					{ nat->in_flags |= IPN_AUTOPORTMAP;
    864 					  nat->in_spmin = 1024;
    865 					  nat->in_spmax = 65535;
    866 					}
    867 	| IPNY_ICMPIDMAP YY_STR portpair sequential
    868 			{ if (strcmp($2, "icmp") != 0 &&
    869 			      strcmp($2, "ipv6-icmp") != 0) {
    870 				yyerror("icmpidmap not followed by icmp");
    871 			  }
    872 			  free($2);
    873 			  if ($3.p1 < 0 || $3.p1 > 65535)
    874 				yyerror("invalid 1st ICMP Id number");
    875 			  if ($3.p2 < 0 || $3.p2 > 65535)
    876 				yyerror("invalid 2nd ICMP Id number");
    877 			  if (strcmp($2, "ipv6-icmp") == 0) {
    878 				nat->in_pr[0] = IPPROTO_ICMPV6;
    879 				nat->in_pr[1] = IPPROTO_ICMPV6;
    880 			  } else {
    881 				nat->in_pr[0] = IPPROTO_ICMP;
    882 				nat->in_pr[1] = IPPROTO_ICMP;
    883 			  }
    884 			  nat->in_flags = IPN_ICMPQUERY;
    885 			  nat->in_spmin = $3.p1;
    886 			  nat->in_spmax = $3.p2;
    887 			}
    888 	;
    889 
    890 sobject:
    891 	saddr				{ $$ = $1; }
    892 	| saddr port portstuff		{ nat->in_osport = $3.p1;
    893 					  nat->in_stop = $3.p2;
    894 					  nat->in_scmp = $3.pc;
    895 					  $$ = $1;
    896 					}
    897 	;
    898 
    899 saddr:	addr				{ nat->in_osrcatype = $1.t;
    900 					  bcopy(&$1.a,
    901 						&nat->in_osrc.na_addr[0],
    902 						sizeof($1.a));
    903 					  bcopy(&$1.m,
    904 						&nat->in_osrc.na_addr[1],
    905 						sizeof($1.m));
    906 					  $$ = $1.f;
    907 					}
    908 	;
    909 
    910 dobject:
    911 	daddr				{ $$ = $1; }
    912 	| daddr port portstuff		{ nat->in_odport = $3.p1;
    913 					  nat->in_dtop = $3.p2;
    914 					  nat->in_dcmp = $3.pc;
    915 					  $$ = $1;
    916 					}
    917 	;
    918 
    919 daddr:	addr				{ nat->in_odstatype = $1.t;
    920 					  bcopy(&$1.a,
    921 						&nat->in_odst.na_addr[0],
    922 						sizeof($1.a));
    923 					  bcopy(&$1.m,
    924 						&nat->in_odst.na_addr[1],
    925 						sizeof($1.m));
    926 					  $$ = $1.f;
    927 					}
    928 	;
    929 
    930 addr:	IPNY_ANY			{ yyexpectaddr = 0;
    931 					  bzero(&$$, sizeof($$));
    932 					  $$.t = FRI_NORMAL;
    933 					}
    934 	| hostname			{ bzero(&$$, sizeof($$));
    935 					  $$.a = $1.a;
    936 					  $$.t = FRI_NORMAL;
    937 					  $$.v = ftov($1.f);
    938 					  $$.f = $1.f;
    939 					  if ($$.f == AF_INET) {
    940 						  $$.m.in4.s_addr = 0xffffffff;
    941 					  } else if ($$.f == AF_INET6) {
    942 						  $$.m.i6[0] = 0xffffffff;
    943 						  $$.m.i6[1] = 0xffffffff;
    944 						  $$.m.i6[2] = 0xffffffff;
    945 						  $$.m.i6[3] = 0xffffffff;
    946 					  }
    947 					  yyexpectaddr = 0;
    948 					}
    949 	| hostname slash YY_NUMBER
    950 					{ bzero(&$$, sizeof($$));
    951 					  $$.a = $1.a;
    952 					  $$.f = $1.f;
    953 					  $$.v = ftov($1.f);
    954 					  $$.t = FRI_NORMAL;
    955 					  ntomask($$.f, $3, (u_32_t *)&$$.m);
    956 					  $$.a.i6[0] &= $$.m.i6[0];
    957 					  $$.a.i6[1] &= $$.m.i6[1];
    958 					  $$.a.i6[2] &= $$.m.i6[2];
    959 					  $$.a.i6[3] &= $$.m.i6[3];
    960 					  yyexpectaddr = 0;
    961 					}
    962 	| hostname slash ipaddr		{ bzero(&$$, sizeof($$));
    963 					  if ($1.f != $3.f) {
    964 						yyerror("1.address family "
    965 							"mismatch");
    966 					  }
    967 					  $$.a = $1.a;
    968 					  $$.m = $3.a;
    969 					  $$.t = FRI_NORMAL;
    970 					  $$.a.i6[0] &= $$.m.i6[0];
    971 					  $$.a.i6[1] &= $$.m.i6[1];
    972 					  $$.a.i6[2] &= $$.m.i6[2];
    973 					  $$.a.i6[3] &= $$.m.i6[3];
    974 					  $$.f = $1.f;
    975 					  $$.v = ftov($1.f);
    976 					  yyexpectaddr = 0;
    977 					}
    978 	| hostname slash hexnumber	{ bzero(&$$, sizeof($$));
    979 					  $$.a = $1.a;
    980 					  $$.m.in4.s_addr = htonl($3);
    981 					  $$.t = FRI_NORMAL;
    982 					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
    983 					  $$.f = $1.f;
    984 					  $$.v = ftov($1.f);
    985 					  if ($$.f == AF_INET6)
    986 						yyerror("incorrect inet6 mask");
    987 					}
    988 	| hostname mask ipaddr		{ bzero(&$$, sizeof($$));
    989 					  if ($1.f != $3.f) {
    990 						yyerror("2.address family "
    991 							"mismatch");
    992 					  }
    993 					  $$.a = $1.a;
    994 					  $$.m = $3.a;
    995 					  $$.t = FRI_NORMAL;
    996 					  $$.a.i6[0] &= $$.m.i6[0];
    997 					  $$.a.i6[1] &= $$.m.i6[1];
    998 					  $$.a.i6[2] &= $$.m.i6[2];
    999 					  $$.a.i6[3] &= $$.m.i6[3];
   1000 					  $$.f = $1.f;
   1001 					  $$.v = ftov($1.f);
   1002 					  yyexpectaddr = 0;
   1003 					}
   1004 	| hostname mask hexnumber	{ bzero(&$$, sizeof($$));
   1005 					  $$.a = $1.a;
   1006 					  $$.m.in4.s_addr = htonl($3);
   1007 					  $$.t = FRI_NORMAL;
   1008 					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
   1009 					  $$.f = AF_INET;
   1010 					  $$.v = 4;
   1011 					}
   1012 	| pool slash YY_NUMBER		{ bzero(&$$, sizeof($$));
   1013 					  $$.a.iplookupnum = $3;
   1014 					  $$.a.iplookuptype = IPLT_POOL;
   1015 					  $$.a.iplookupsubtype = 0;
   1016 					  $$.t = FRI_LOOKUP;
   1017 					}
   1018 	| pool slash YY_STR		{ bzero(&$$, sizeof($$));
   1019 					  $$.a.iplookupname = addname(&nat,$3);
   1020 					  $$.a.iplookuptype = IPLT_POOL;
   1021 					  $$.a.iplookupsubtype = 1;
   1022 					  $$.t = FRI_LOOKUP;
   1023 					}
   1024 	| hash slash YY_NUMBER		{ bzero(&$$, sizeof($$));
   1025 					  $$.a.iplookupnum = $3;
   1026 					  $$.a.iplookuptype = IPLT_HASH;
   1027 					  $$.a.iplookupsubtype = 0;
   1028 					  $$.t = FRI_LOOKUP;
   1029 					}
   1030 	| hash slash YY_STR		{ bzero(&$$, sizeof($$));
   1031 					  $$.a.iplookupname = addname(&nat,$3);
   1032 					  $$.a.iplookuptype = IPLT_HASH;
   1033 					  $$.a.iplookupsubtype = 1;
   1034 					  $$.t = FRI_LOOKUP;
   1035 					}
   1036 	;
   1037 
   1038 slash:	'/'				{ yyexpectaddr = 0; }
   1039 	;
   1040 
   1041 mask:	IPNY_MASK			{ yyexpectaddr = 0; }
   1042 	;
   1043 
   1044 pool:	IPNY_POOL			{ if (!(nat->in_flags & IPN_FILTER)) {
   1045 						yyerror("Can only use pool with from/to rules\n");
   1046 					  }
   1047 					  yyexpectaddr = 0;
   1048 					  yyresetdict();
   1049 					}
   1050 	;
   1051 
   1052 hash:	IPNY_HASH			{ if (!(nat->in_flags & IPN_FILTER)) {
   1053 						yyerror("Can only use hash with from/to rules\n");
   1054 					  }
   1055 					  yyexpectaddr = 0;
   1056 					  yyresetdict();
   1057 					}
   1058 	;
   1059 
   1060 portstuff:
   1061 	compare portspec		{ $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
   1062 	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
   1063 	;
   1064 
   1065 mapoptions:
   1066 	rr frag age mssclamp nattag setproto purge
   1067 	;
   1068 
   1069 rdroptions:
   1070 	rr frag age sticky mssclamp rdrproxy nattag purge
   1071 	;
   1072 
   1073 nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
   1074 						  sizeof(nat->in_tag.ipt_tag));
   1075 					}
   1076 rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
   1077 	;
   1078 
   1079 frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
   1080 	;
   1081 
   1082 age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
   1083 						  nat->in_age[1] = $2; }
   1084 	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
   1085 						  nat->in_age[1] = $4; }
   1086 	;
   1087 
   1088 sticky: | IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
   1089 					      !(nat->in_flags & IPN_SPLIT)) {
   1090 						FPRINTF(stderr,
   1091 		"'sticky' for use with round-robin/IP splitting only\n");
   1092 					  } else
   1093 						nat->in_flags |= IPN_STICKY;
   1094 					}
   1095 	;
   1096 
   1097 mssclamp:
   1098 	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
   1099 	;
   1100 
   1101 tcpudp:	IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
   1102 	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
   1103 	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
   1104 					  nat->in_pr[0] = 0;
   1105 					  nat->in_pr[1] = 0;
   1106 					}
   1107 	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
   1108 					  nat->in_pr[0] = 0;
   1109 					  nat->in_pr[1] = 0;
   1110 					}
   1111 	;
   1112 
   1113 sequential:
   1114 	| IPNY_SEQUENTIAL		{ nat->in_flags |= IPN_SEQUENTIAL; }
   1115 	;
   1116 
   1117 purge:
   1118 	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
   1119 	;
   1120 
   1121 rdrproxy:
   1122 	IPNY_PROXY YY_STR
   1123 					{ int pos;
   1124 					  pos = addname(&nat, $2);
   1125 					  nat->in_plabel = pos;
   1126 					  nat->in_odport = nat->in_dpnext;
   1127 					  nat->in_dtop = nat->in_odport;
   1128 					  free($2);
   1129 					}
   1130 	| proxy			{ if (nat->in_plabel != -1) {
   1131 					nat->in_ndport = nat->in_odport;
   1132 					nat->in_dpmin = nat->in_odport;
   1133 					nat->in_dpmax = nat->in_dpmin;
   1134 					nat->in_dtop = nat->in_dpmin;
   1135 					nat->in_dpnext = nat->in_dpmin;
   1136 				  }
   1137 				}
   1138 	;
   1139 
   1140 newopts:
   1141 	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
   1142 	;
   1143 
   1144 proto:	YY_NUMBER			{ $$ = $1;
   1145 					  if ($$ != IPPROTO_TCP &&
   1146 					      $$ != IPPROTO_UDP)
   1147 						suggest_port = 0;
   1148 					}
   1149 	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
   1150 	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
   1151 	| YY_STR			{ $$ = getproto($1);
   1152 					  free($1);
   1153 					  if ($$ == -1)
   1154 						yyerror("unknown protocol");
   1155 					  if ($$ != IPPROTO_TCP &&
   1156 					      $$ != IPPROTO_UDP)
   1157 						suggest_port = 0;
   1158 					}
   1159 	;
   1160 
   1161 hexnumber:
   1162 	YY_HEX				{ $$ = $1; }
   1163 	;
   1164 
   1165 hostname:
   1166 	YY_STR				{ i6addr_t addr;
   1167 					  int family;
   1168 
   1169 #ifdef USE_INET6
   1170 					  if (nat->in_v[0] == 6)
   1171 						family = AF_INET6;
   1172 					  else
   1173 #endif
   1174 						family = AF_INET;
   1175 					  memset(&($$), 0, sizeof($$));
   1176 					  memset(&addr, 0, sizeof(addr));
   1177 					  $$.f = family;
   1178 					  if (gethost(family, $1,
   1179 						      &addr) == 0) {
   1180 						$$.a = addr;
   1181 					  } else {
   1182 						FPRINTF(stderr,
   1183 							"Unknown host '%s'\n",
   1184 							$1);
   1185 					  }
   1186 					  free($1);
   1187 					}
   1188 	| YY_NUMBER			{ memset(&($$), 0, sizeof($$));
   1189 					  $$.a.in4.s_addr = htonl($1);
   1190 					  if ($$.a.in4.s_addr != 0)
   1191 						$$.f = AF_INET;
   1192 					}
   1193 	| ipv4				{ $$ = $1; }
   1194 	| YY_IPV6			{ memset(&($$), 0, sizeof($$));
   1195 					  $$.a = $1;
   1196 					  $$.f = AF_INET6;
   1197 					}
   1198 	| YY_NUMBER YY_IPV6		{ memset(&($$), 0, sizeof($$));
   1199 					  $$.a = $2;
   1200 					  $$.f = AF_INET6;
   1201 					}
   1202 	;
   1203 
   1204 compare:
   1205 	'='				{ $$ = FR_EQUAL; }
   1206 	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
   1207 	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
   1208 	| YY_CMP_LT			{ $$ = FR_LESST; }
   1209 	| YY_CMP_LE			{ $$ = FR_LESSTE; }
   1210 	| YY_CMP_GT			{ $$ = FR_GREATERT; }
   1211 	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
   1212 
   1213 range:
   1214 	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
   1215 	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
   1216 	| ':'				{ $$ = FR_INCRANGE; }
   1217 	;
   1218 
   1219 ipaddr:	ipv4				{ $$ = $1; }
   1220 	| YY_IPV6			{ $$.a = $1;
   1221 					  $$.f = AF_INET6;
   1222 					}
   1223 	;
   1224 
   1225 ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
   1226 		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
   1227 			yyerror("Invalid octet string for IP address");
   1228 			return 0;
   1229 		  }
   1230 		  bzero((char *)&$$, sizeof($$));
   1231 		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
   1232 		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
   1233 		  $$.f = AF_INET;
   1234 		}
   1235 	;
   1236 
   1237 %%
   1238 
   1239 
   1240 static	wordtab_t	proxies[] = {
   1241 	{ "dns",	IPNY_DNS }
   1242 };
   1243 
   1244 static	wordtab_t	dnswords[] = {
   1245 	{ "allow",	IPNY_ALLOW },
   1246 	{ "block",	IPNY_DENY },
   1247 	{ "deny",	IPNY_DENY },
   1248 	{ "drop",	IPNY_DENY },
   1249 	{ "pass",	IPNY_ALLOW },
   1250 
   1251 };
   1252 
   1253 static	wordtab_t	yywords[] = {
   1254 	{ "age",	IPNY_AGE },
   1255 	{ "any",	IPNY_ANY },
   1256 	{ "auto",	IPNY_AUTO },
   1257 	{ "bimap",	IPNY_BIMAP },
   1258 	{ "config",	IPNY_CONFIG },
   1259 	{ "divert",	IPNY_DIVERT },
   1260 	{ "dst",	IPNY_DST },
   1261 	{ "dstlist",	IPNY_DSTLIST },
   1262 	{ "frag",	IPNY_FRAG },
   1263 	{ "from",	IPNY_FROM },
   1264 	{ "hash",	IPNY_HASH },
   1265 	{ "icmpidmap",	IPNY_ICMPIDMAP },
   1266 	{ "in",		IPNY_IN },
   1267 	{ "inet",	IPNY_INET },
   1268 	{ "inet6",	IPNY_INET6 },
   1269 	{ "mask",	IPNY_MASK },
   1270 	{ "map",	IPNY_MAP },
   1271 	{ "map-block",	IPNY_MAPBLOCK },
   1272 	{ "mssclamp",	IPNY_MSSCLAMP },
   1273 	{ "netmask",	IPNY_MASK },
   1274 	{ "no",		IPNY_NO },
   1275 	{ "on",		IPNY_ON },
   1276 	{ "out",	IPNY_OUT },
   1277 	{ "pool",	IPNY_POOL },
   1278 	{ "port",	IPNY_PORT },
   1279 	{ "portmap",	IPNY_PORTMAP },
   1280 	{ "ports",	IPNY_PORTS },
   1281 	{ "proto",	IPNY_PROTO },
   1282 	{ "proxy",	IPNY_PROXY },
   1283 	{ "purge",	IPNY_PURGE },
   1284 	{ "range",	IPNY_RANGE },
   1285 	{ "rewrite",	IPNY_REWRITE },
   1286 	{ "rdr",	IPNY_RDR },
   1287 	{ "round-robin",IPNY_ROUNDROBIN },
   1288 	{ "sequential",	IPNY_SEQUENTIAL },
   1289 	{ "src",	IPNY_SRC },
   1290 	{ "sticky",	IPNY_STICKY },
   1291 	{ "tag",	IPNY_TAG },
   1292 	{ "tcp",	IPNY_TCP },
   1293 	{ "tcpudp",	IPNY_TCPUDP },
   1294 	{ "to",		IPNY_TO },
   1295 	{ "udp",	IPNY_UDP },
   1296 	{ "-",		'-' },
   1297 	{ "->",		IPNY_TLATE },
   1298 	{ "eq",		YY_CMP_EQ },
   1299 	{ "ne",		YY_CMP_NE },
   1300 	{ "lt",		YY_CMP_LT },
   1301 	{ "gt",		YY_CMP_GT },
   1302 	{ "le",		YY_CMP_LE },
   1303 	{ "ge",		YY_CMP_GE },
   1304 	{ NULL,		0 }
   1305 };
   1306 
   1307 
   1308 int
   1309 ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
   1310 	int fd;
   1311 	addfunc_t addfunc;
   1312 	ioctlfunc_t ioctlfunc;
   1313 	char *filename;
   1314 {
   1315 	FILE *fp = NULL;
   1316 	int rval;
   1317 	char *s;
   1318 
   1319 	yylineNum = 1;
   1320 
   1321 	(void) yysettab(yywords);
   1322 
   1323 	s = getenv("YYDEBUG");
   1324 	if (s)
   1325 		yydebug = atoi(s);
   1326 	else
   1327 		yydebug = 0;
   1328 
   1329 	if (strcmp(filename, "-")) {
   1330 		fp = fopen(filename, "r");
   1331 		if (!fp) {
   1332 			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
   1333 				STRERROR(errno));
   1334 			return -1;
   1335 		}
   1336 	} else
   1337 		fp = stdin;
   1338 
   1339 	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
   1340 		;
   1341 	if (fp != NULL)
   1342 		fclose(fp);
   1343 	if (rval == -1)
   1344 		rval = 0;
   1345 	else if (rval != 0)
   1346 		rval = 1;
   1347 	return rval;
   1348 }
   1349 
   1350 
   1351 int
   1352 ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
   1353 	int fd;
   1354 	addfunc_t addfunc;
   1355 	ioctlfunc_t ioctlfunc;
   1356 	FILE *fp;
   1357 {
   1358 	char *s;
   1359 	int i;
   1360 
   1361 	natfd = fd;
   1362 	parser_error = 0;
   1363 	nataddfunc = addfunc;
   1364 	natioctlfunc = ioctlfunc;
   1365 
   1366 	if (feof(fp))
   1367 		return -1;
   1368 	i = fgetc(fp);
   1369 	if (i == EOF)
   1370 		return -1;
   1371 	if (ungetc(i, fp) == EOF)
   1372 		return -1;
   1373 	if (feof(fp))
   1374 		return -1;
   1375 	s = getenv("YYDEBUG");
   1376 	if (s)
   1377 		yydebug = atoi(s);
   1378 	else
   1379 		yydebug = 0;
   1380 
   1381 	yyin = fp;
   1382 	yyparse();
   1383 	return parser_error;
   1384 }
   1385 
   1386 
   1387 static void
   1388 newnatrule()
   1389 {
   1390 	ipnat_t *n;
   1391 
   1392 	n = calloc(1, sizeof(*n));
   1393 	if (n == NULL)
   1394 		return;
   1395 
   1396 	if (nat == NULL) {
   1397 		nattop = nat = n;
   1398 		n->in_pnext = &nattop;
   1399 	} else {
   1400 		nat->in_next = n;
   1401 		n->in_pnext = &nat->in_next;
   1402 		nat = n;
   1403 	}
   1404 
   1405 	n->in_flineno = yylineNum;
   1406 	n->in_ifnames[0] = -1;
   1407 	n->in_ifnames[1] = -1;
   1408 	n->in_plabel = -1;
   1409 	n->in_pconfig = -1;
   1410 	n->in_size = sizeof(*n);
   1411 
   1412 	suggest_port = 0;
   1413 }
   1414 
   1415 
   1416 static void
   1417 setnatproto(p)
   1418 	int p;
   1419 {
   1420 	nat->in_pr[0] = p;
   1421 	nat->in_pr[1] = p;
   1422 
   1423 	switch (p)
   1424 	{
   1425 	case IPPROTO_TCP :
   1426 		nat->in_flags |= IPN_TCP;
   1427 		nat->in_flags &= ~IPN_UDP;
   1428 		break;
   1429 	case IPPROTO_UDP :
   1430 		nat->in_flags |= IPN_UDP;
   1431 		nat->in_flags &= ~IPN_TCP;
   1432 		break;
   1433 #ifdef USE_INET6
   1434 	case IPPROTO_ICMPV6 :
   1435 #endif
   1436 	case IPPROTO_ICMP :
   1437 		nat->in_flags &= ~IPN_TCPUDP;
   1438 		if (!(nat->in_flags & IPN_ICMPQUERY) &&
   1439 		    !(nat->in_redir & NAT_DIVERTUDP)) {
   1440 			nat->in_dcmp = 0;
   1441 			nat->in_scmp = 0;
   1442 			nat->in_dpmin = 0;
   1443 			nat->in_dpmax = 0;
   1444 			nat->in_dpnext = 0;
   1445 			nat->in_spmin = 0;
   1446 			nat->in_spmax = 0;
   1447 			nat->in_spnext = 0;
   1448 		}
   1449 		break;
   1450 	default :
   1451 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
   1452 			nat->in_flags &= ~IPN_TCPUDP;
   1453 			nat->in_dcmp = 0;
   1454 			nat->in_scmp = 0;
   1455 			nat->in_dpmin = 0;
   1456 			nat->in_dpmax = 0;
   1457 			nat->in_dpnext = 0;
   1458 			nat->in_spmin = 0;
   1459 			nat->in_spmax = 0;
   1460 			nat->in_spnext = 0;
   1461 		}
   1462 		break;
   1463 	}
   1464 
   1465 	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
   1466 		nat->in_stop = 0;
   1467 		nat->in_dtop = 0;
   1468 		nat->in_osport = 0;
   1469 		nat->in_odport = 0;
   1470 		nat->in_stop = 0;
   1471 		nat->in_osport = 0;
   1472 		nat->in_dtop = 0;
   1473 		nat->in_odport = 0;
   1474 	}
   1475 	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
   1476 		nat->in_flags &= ~IPN_FIXEDDPORT;
   1477 }
   1478 
   1479 
   1480 int
   1481 ipnat_addrule(fd, ioctlfunc, ptr)
   1482 	int fd;
   1483 	ioctlfunc_t ioctlfunc;
   1484 	void *ptr;
   1485 {
   1486 	ioctlcmd_t add, del;
   1487 	ipfobj_t obj;
   1488 	ipnat_t *ipn;
   1489 
   1490 	ipn = ptr;
   1491 	bzero((char *)&obj, sizeof(obj));
   1492 	obj.ipfo_rev = IPFILTER_VERSION;
   1493 	obj.ipfo_size = ipn->in_size;
   1494 	obj.ipfo_type = IPFOBJ_IPNAT;
   1495 	obj.ipfo_ptr = ptr;
   1496 
   1497 	if ((opts & OPT_DONOTHING) != 0)
   1498 		fd = -1;
   1499 
   1500 	if (opts & OPT_ZERORULEST) {
   1501 		add = SIOCZRLST;
   1502 		del = 0;
   1503 	} else if (opts & OPT_PURGE) {
   1504 		add = 0;
   1505 		del = SIOCPURGENAT;
   1506 	} else {
   1507 		add = SIOCADNAT;
   1508 		del = SIOCRMNAT;
   1509 	}
   1510 
   1511 	if ((opts & OPT_VERBOSE) != 0)
   1512 		printnat(ipn, opts);
   1513 
   1514 	if (opts & OPT_DEBUG)
   1515 		binprint(ipn, ipn->in_size);
   1516 
   1517 	if ((opts & OPT_ZERORULEST) != 0) {
   1518 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
   1519 			if ((opts & OPT_DONOTHING) == 0) {
   1520 				char msg[80];
   1521 
   1522 				sprintf(msg, "%d:ioctl(zero nat rule)",
   1523 					ipn->in_flineno);
   1524 				return ipf_perror_fd(fd, ioctlfunc, msg);
   1525 			}
   1526 		} else {
   1527 			PRINTF("hits %lu ", ipn->in_hits);
   1528 #ifdef USE_QUAD_T
   1529 			PRINTF("bytes %"PRIu64" ",
   1530 			       ipn->in_bytes[0] + ipn->in_bytes[1]);
   1531 #else
   1532 			PRINTF("bytes %lu ",
   1533 			       ipn->in_bytes[0] + ipn->in_bytes[1]);
   1534 #endif
   1535 			printnat(ipn, opts);
   1536 		}
   1537 	} else if ((opts & OPT_REMOVE) != 0) {
   1538 		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
   1539 			if ((opts & OPT_DONOTHING) == 0) {
   1540 				char msg[80];
   1541 
   1542 				sprintf(msg, "%d:ioctl(delete nat rule)",
   1543 					ipn->in_flineno);
   1544 				return ipf_perror_fd(fd, ioctlfunc, msg);
   1545 			}
   1546 		}
   1547 	} else {
   1548 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
   1549 			if ((opts & OPT_DONOTHING) == 0) {
   1550 				char msg[80];
   1551 
   1552 				sprintf(msg, "%d:ioctl(add/insert nat rule)",
   1553 					ipn->in_flineno);
   1554 				if (errno == EEXIST) {
   1555 					sprintf(msg + strlen(msg), "(line %d)",
   1556 						ipn->in_flineno);
   1557 				}
   1558 				return ipf_perror_fd(fd, ioctlfunc, msg);
   1559 			}
   1560 		}
   1561 	}
   1562 	return 0;
   1563 }
   1564 
   1565 
   1566 static void
   1567 setmapifnames()
   1568 {
   1569 	if (nat->in_ifnames[1] == -1)
   1570 		nat->in_ifnames[1] = nat->in_ifnames[0];
   1571 
   1572 	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
   1573 		nat->in_flags |= IPN_TCPUDP;
   1574 
   1575 	if ((nat->in_flags & IPN_TCPUDP) == 0)
   1576 		setnatproto(nat->in_pr[1]);
   1577 
   1578 	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
   1579 	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
   1580 		nat_setgroupmap(nat);
   1581 }
   1582 
   1583 
   1584 static void
   1585 setrdrifnames()
   1586 {
   1587 	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
   1588 		nat->in_flags |= IPN_TCPUDP;
   1589 
   1590 	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
   1591 	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
   1592 		setnatproto(IPPROTO_TCP);
   1593 
   1594 	if (nat->in_ifnames[1] == -1)
   1595 		nat->in_ifnames[1] = nat->in_ifnames[0];
   1596 }
   1597 
   1598 
   1599 static void
   1600 proxy_setconfig(proxy)
   1601 	int proxy;
   1602 {
   1603 	if (proxy == IPNY_DNS) {
   1604 		yysetfixeddict(dnswords);
   1605 	}
   1606 }
   1607 
   1608 
   1609 static void
   1610 proxy_unsetconfig()
   1611 {
   1612 	yyresetdict();
   1613 }
   1614 
   1615 
   1616 static namelist_t *
   1617 proxy_dns_add_pass(prefix, name)
   1618 	char *prefix, *name;
   1619 {
   1620 	namelist_t *n;
   1621 
   1622 	n = calloc(1, sizeof(*n));
   1623 	if (n != NULL) {
   1624 		if (prefix == NULL || *prefix == '\0') {
   1625 			n->na_name = strdup(name);
   1626 		} else {
   1627 			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
   1628 			strcpy(n->na_name, prefix);
   1629 			strcat(n->na_name, name);
   1630 		}
   1631 	}
   1632 	return n;
   1633 }
   1634 
   1635 
   1636 static namelist_t *
   1637 proxy_dns_add_block(prefix, name)
   1638 	char *prefix, *name;
   1639 {
   1640 	namelist_t *n;
   1641 
   1642 	n = calloc(1, sizeof(*n));
   1643 	if (n != NULL) {
   1644 		if (prefix == NULL || *prefix == '\0') {
   1645 			n->na_name = strdup(name);
   1646 		} else {
   1647 			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
   1648 			strcpy(n->na_name, prefix);
   1649 			strcat(n->na_name, name);
   1650 		}
   1651 		n->na_value = 1;
   1652 	}
   1653 	return n;
   1654 }
   1655 
   1656 
   1657 static void
   1658 proxy_addconfig(proxy, proto, conf, list)
   1659 	char *proxy, *conf;
   1660 	int proto;
   1661 	namelist_t *list;
   1662 {
   1663 	proxyrule_t *pr;
   1664 
   1665 	pr = calloc(1, sizeof(*pr));
   1666 	if (pr != NULL) {
   1667 		pr->pr_proto = proto;
   1668 		pr->pr_proxy = proxy;
   1669 		pr->pr_conf = conf;
   1670 		pr->pr_names = list;
   1671 		pr->pr_next = prules;
   1672 		prules = pr;
   1673 	}
   1674 }
   1675 
   1676 
   1677 static void
   1678 proxy_loadrules(fd, ioctlfunc, rules)
   1679 	int fd;
   1680 	ioctlfunc_t ioctlfunc;
   1681 	proxyrule_t *rules;
   1682 {
   1683 	proxyrule_t *pr;
   1684 
   1685 	while ((pr = rules) != NULL) {
   1686 		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
   1687 				 pr->pr_conf, pr->pr_names);
   1688 		rules = pr->pr_next;
   1689 		free(pr->pr_conf);
   1690 		free(pr);
   1691 	}
   1692 }
   1693 
   1694 
   1695 static void
   1696 proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
   1697 	int fd;
   1698 	ioctlfunc_t ioctlfunc;
   1699 	char *proxy, *conf;
   1700 	int proto;
   1701 	namelist_t *list;
   1702 {
   1703 	namelist_t *na;
   1704 	ipfobj_t obj;
   1705 	ap_ctl_t pcmd;
   1706 
   1707 	obj.ipfo_rev = IPFILTER_VERSION;
   1708 	obj.ipfo_type = IPFOBJ_PROXYCTL;
   1709 	obj.ipfo_size = sizeof(pcmd);
   1710 	obj.ipfo_ptr = &pcmd;
   1711 
   1712 	while ((na = list) != NULL) {
   1713 		if ((opts & OPT_REMOVE) != 0)
   1714 			pcmd.apc_cmd = APC_CMD_DEL;
   1715 		else
   1716 			pcmd.apc_cmd = APC_CMD_ADD;
   1717 		pcmd.apc_dsize = strlen(na->na_name) + 1;
   1718 		pcmd.apc_data = na->na_name;
   1719 		pcmd.apc_arg = na->na_value;
   1720 		pcmd.apc_p = proto;
   1721 
   1722 		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
   1723 		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
   1724 
   1725 		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
   1726 		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
   1727 
   1728 		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
   1729                         if ((opts & OPT_DONOTHING) == 0) {
   1730                                 char msg[80];
   1731 
   1732                                 sprintf(msg, "%d:ioctl(add/remove proxy rule)",
   1733 					yylineNum);
   1734                                 ipf_perror_fd(fd, ioctlfunc, msg);
   1735 				return;
   1736                         }
   1737 		}
   1738 
   1739 		list = na->na_next;
   1740 		free(na->na_name);
   1741 		free(na);
   1742 	}
   1743 }
   1744 
   1745 
   1746 static void
   1747 setifname(np, idx, name)
   1748 	ipnat_t **np;
   1749 	int idx;
   1750 	char *name;
   1751 {
   1752 	int pos;
   1753 
   1754 	pos = addname(np, name);
   1755 	if (pos == -1)
   1756 		return;
   1757 	(*np)->in_ifnames[idx] = pos;
   1758 }
   1759 
   1760 
   1761 static int
   1762 addname(np, name)
   1763 	ipnat_t **np;
   1764 	char *name;
   1765 {
   1766 	ipnat_t *n;
   1767 	int nlen;
   1768 	int pos;
   1769 
   1770 	nlen = strlen(name) + 1;
   1771 	n = calloc(1, (*np)->in_size + nlen);
   1772 	memcpy(n, *np, (*np)->in_size);
   1773 	free(*np);
   1774 	if (*np == nattop)
   1775 		nattop = n;
   1776 	*np = n;
   1777 	if (n == NULL)
   1778 		return -1;
   1779 	if (n->in_pnext != NULL)
   1780 		*n->in_pnext = n;
   1781 	n->in_size += nlen;
   1782 	pos = n->in_namelen;
   1783 	n->in_namelen += nlen;
   1784 	strcpy(n->in_names + pos, name);
   1785 	n->in_names[n->in_namelen] = '\0';
   1786 	return pos;
   1787 }
   1788