1 /*
2  *  Copyright (c) 2016-2020, Peter Haag
3  *  Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
4  *  All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are met:
8  *
9  *   * Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *   * Redistributions in binary form must reproduce the above copyright notice,
12  *     this list of conditions and the following disclaimer in the documentation
13  *     and/or other materials provided with the distribution.
14  *   * Neither the name of the author nor the names of its contributors may be
15  *     used to endorse or promote products derived from this software without
16  *     specific prior written permission.
17  *
18  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  *  POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 
32 %{
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <ctype.h>
46 
47 #ifdef HAVE_STDINT_H
48 #include <stdint.h>
49 #endif
50 
51 #include "util.h"
52 #include "output_util.h"
53 #include "rbtree.h"
54 #include "filter.h"
55 #include "nfdump.h"
56 #include "nffile.h"
57 #include "nftree.h"
58 #include "ipconv.h"
59 
60 #define AnyMask 0xffffffffffffffffLL
61 
62 /*
63  * function prototypes
64  */
65 static void  yyerror(char *msg);
66 
67 static uint32_t ChainHosts(uint64_t *offsets, uint64_t *hostlist, int num_records, int type);
68 
69 static uint64_t VerifyMac(char *s);
70 
71 static int InitSymbols(void);
72 
73 static uint32_t Get_fwd_status_id(char *status);
74 
75 enum { DIR_UNSPEC = 1,
76 	   SOURCE, DESTINATION, SOURCE_AND_DESTINATION, SOURCE_OR_DESTINATION,
77 	   DIR_IN, DIR_OUT,
78 	   IN_SRC, IN_DST, OUT_SRC, OUT_DST,
79 	   ADJ_PREV, ADJ_NEXT };
80 
81 enum { IS_START = 0, IS_END };
82 
83 /* var defs */
84 extern int 			lineno;
85 extern char 		*yytext;
86 extern uint64_t		*IPstack;
87 extern uint32_t	StartNode;
88 extern uint16_t	Extended;
89 extern int (*FilterEngine)(uint32_t *);
90 extern char	*FilterFilename;
91 
92 static uint32_t num_ip;
93 
94 static struct fwd_status_def_s {
95 	uint32_t	id;
96 	char		*name;
97 } fwd_status_def_list[] = {
98 	{ 0,	"Ukwn"}, 	// Unknown
99 	{ 1,	"Forw"}, 	// Normal forwarding
100 	{ 2,	"Frag"}, 	// Fragmented
101 	{ 16,	"Drop"}, 	// Drop
102 	{ 17,	"DaclD"},	// Drop ACL deny
103 	{ 18,	"Daclp"},	// Drop ACL drop
104 	{ 19,	"Noroute"},	// Unroutable
105 	{ 20,	"Dadj"}, 	// Drop Adjacency
106 	{ 21,	"Dfrag"}, 	// Drop Fragmentation & DF set
107 	{ 22,	"Dbadh"}, 	// Drop Bad header checksum
108 	{ 23,	"Dbadtlen"}, // Drop Bad total Length
109 	{ 24,	"Dbadhlen"}, // Drop Bad Header Length
110 	{ 25,	"DbadTTL"}, // Drop bad TTL
111 	{ 26,	"Dpolicy"}, // Drop Policer
112 	{ 27,	"Dwred"}, 	// Drop WRED
113 	{ 28,	"Drpf"}, 	// Drop RPF
114 	{ 29,	"Dforus"}, 	// Drop For us
115 	{ 30,	"DbadOf"}, 	// Drop Bad output interface
116 	{ 31,	"Dhw"}, 	// Drop Hardware
117 	{ 128,	"Term"}, 	// Terminate
118 	{ 129,	"Tadj"}, 	// Terminate Punt Adjacency
119 	{ 130,	"TincAdj"}, // Terminate Incomplete Adjacency
120 	{ 131,	"Tforus"}, 	// Terminate For us
121 	{ 0,	NULL}		// Last entry
122 };
123 
124 static char **fwd_status = NULL;
125 
126 char yyerror_buff[256];
127 
128 #define MPLSMAX 0x00ffffff
129 %}
130 
131 %union {
132 	uint64_t		value;
133 	char			*s;
134 	FilterParam_t	param;
135 	void			*list;
136 }
137 
138 %token ANY IP IF MAC MPLS TOS DIR FLAGS PROTO MASK HOSTNAME NET PORT FWDSTAT IN OUT SRC DST EQ LT GT PREV NEXT
139 %token NUMBER STRING IDENT PORTNUM ICMP_TYPE ICMP_CODE ENGINE_TYPE ENGINE_ID AS PACKETS BYTES FLOWS
140 %token PPS BPS BPP DURATION NOT
141 %token IPV4 IPV6 BGPNEXTHOP ROUTER VLAN
142 %token CLIENT SERVER APP LATENCY SYSID
143 %token ASA REASON DENIED XEVENT XIP XNET XPORT INGRESS EGRESS ACL ACE XACE
144 %token NAT ADD EVENT VRF NPORT NIP
145 %token PBLOCK START END STEP SIZE
146 %type <value>	expr NUMBER PORTNUM ICMP_TYPE ICMP_CODE
147 %type <s> STRING REASON
148 %type <param> dqual term comp acl inout
149 %type <list> iplist ullist
150 
151 %left	'+' OR
152 %left	'*' AND
153 %left	NEGATE
154 
155 %%
156 prog: 		/* empty */
157 	| expr 	{
158 		StartNode = $1;
159 	}
160 	;
161 
162 term:	ANY { /* this is an unconditionally true expression, as a filter applies in any case */
163 		$$.self = NewBlock(OffsetProto, 0, 0, CMP_EQ, FUNC_NONE, NULL );
164 	}
165 
166 	| IDENT STRING {
167 		if ( !ScreenIdentString($2) ) {
168 			yyerror("Illegal ident string");
169 			YYABORT;
170 		}
171 
172 		uint32_t	index = AddIdent($2);
173 		$$.self = NewBlock(0, 0, index, CMP_IDENT, FUNC_NONE, NULL );
174 	}
175 
176 	| IPV4 {
177 		$$.self = NewBlock(OffsetRecordFlags, (1LL << ShiftRecordFlags)  & MaskRecordFlags,
178 					(0LL << ShiftRecordFlags)  & MaskRecordFlags, CMP_EQ, FUNC_NONE, NULL);
179 	}
180 
181 	| IPV6 {
182 		$$.self = NewBlock(OffsetRecordFlags, (1LL << ShiftRecordFlags)  & MaskRecordFlags,
183 					(1LL << ShiftRecordFlags)  & MaskRecordFlags, CMP_EQ, FUNC_NONE, NULL);
184 	}
185 
186 	| PROTO NUMBER {
187 		int64_t	proto;
188 		proto = $2;
189 
190 		if ( proto > 255 ) {
191 			yyerror("Protocol number > 255");
192 			YYABORT;
193 		}
194 		if ( proto < 0 ) {
195 			yyerror("Unknown protocol");
196 			YYABORT;
197 		}
198 		$$.self = NewBlock(OffsetProto, MaskProto, (proto << ShiftProto)  & MaskProto, CMP_EQ, FUNC_NONE, NULL);
199 
200 	}
201 
202 	| PROTO STRING {
203 		int64_t	proto;
204 		proto = ProtoNum($2);
205 
206 		if ( proto > 255 ) {
207 			yyerror("Protocol number > 255");
208 			YYABORT;
209 		}
210 		if ( proto < 0 ) {
211 			yyerror("Unknown protocol");
212 			YYABORT;
213 		}
214 		$$.self = NewBlock(OffsetProto, MaskProto, (proto << ShiftProto)  & MaskProto, CMP_EQ, FUNC_NONE, NULL);
215 	}
216 
217 	| dqual PACKETS comp NUMBER {
218 
219 		switch ( $1.direction ) {
220 			case DIR_UNSPEC:
221 			case DIR_IN:
222 				$$.self = NewBlock(OffsetPackets, MaskPackets, $4, $3.comp, FUNC_NONE, NULL);
223 				break;
224 			case DIR_OUT:
225 				$$.self = NewBlock(OffsetOutPackets, MaskPackets, $4, $3.comp, FUNC_NONE, NULL);
226 				break;
227 			default:
228 				/* should never happen */
229 				yyerror("This token is not expected here!");
230 				YYABORT;
231 		} // End of switch
232 
233 	}
234 
235 	| dqual BYTES comp NUMBER {
236 
237 		switch ( $1.direction ) {
238 			case DIR_UNSPEC:
239 			case DIR_IN:
240 				$$.self = NewBlock(OffsetBytes, MaskBytes, $4, $3.comp, FUNC_NONE, NULL);
241 				break;
242 			case DIR_OUT:
243 				$$.self = NewBlock(OffsetOutBytes, MaskBytes, $4, $3.comp, FUNC_NONE, NULL);
244 				break;
245 			default:
246 				yyerror("This token is not expected here!");
247 				YYABORT;
248 		} // End of switch
249 
250 	}
251 
252 	| FLOWS comp NUMBER {
253 			$$.self = NewBlock(OffsetAggrFlows, MaskFlows, $3, $2.comp, FUNC_NONE, NULL);
254 	}
255 
256 	| PPS comp NUMBER {
257 		$$.self = NewBlock(0, AnyMask, $3, $2.comp, FUNC_PPS, NULL);
258 	}
259 
260 	| BPS comp NUMBER {
261 		$$.self = NewBlock(0, AnyMask, $3, $2.comp, FUNC_BPS, NULL);
262 	}
263 
264 	| BPP comp NUMBER {
265 		$$.self = NewBlock(0, AnyMask, $3, $2.comp, FUNC_BPP, NULL);
266 	}
267 
268 	| DURATION comp NUMBER {
269 		$$.self = NewBlock(0, AnyMask, $3, $2.comp, FUNC_DURATION, NULL);
270 	}
271 
272 	| dqual TOS comp NUMBER {
273 		if ( $4 > 255 ) {
274 			yyerror("TOS must be 0..255");
275 			YYABORT;
276 		}
277 
278 		switch ( $1.direction ) {
279 			case DIR_UNSPEC:
280 			case SOURCE:
281 				$$.self = NewBlock(OffsetTos, MaskTos, ($4 << ShiftTos) & MaskTos, $3.comp, FUNC_NONE, NULL);
282 				break;
283 			case DESTINATION:
284 				$$.self = NewBlock(OffsetDstTos, MaskDstTos, ($4 << ShiftDstTos) & MaskDstTos, $3.comp, FUNC_NONE, NULL);
285 				break;
286 			case SOURCE_OR_DESTINATION:
287 				$$.self = Connect_OR(
288 					NewBlock(OffsetTos, MaskTos, ($4 << ShiftTos) & MaskTos, $3.comp, FUNC_NONE, NULL),
289 					NewBlock(OffsetDstTos, MaskDstTos, ($4 << ShiftDstTos) & MaskDstTos, $3.comp, FUNC_NONE, NULL)
290 				);
291 				break;
292 			case SOURCE_AND_DESTINATION:
293 				$$.self = Connect_AND(
294 					NewBlock(OffsetTos, MaskTos, ($4 << ShiftTos) & MaskTos, $3.comp, FUNC_NONE, NULL),
295 					NewBlock(OffsetDstTos, MaskDstTos, ($4 << ShiftDstTos) & MaskDstTos, $3.comp, FUNC_NONE, NULL)
296 				);
297 				break;
298 			default:
299 				yyerror("This token is not expected here!");
300 				YYABORT;
301 			}
302 	}
303 
304 	| FLAGS comp NUMBER	{
305 		if ( $3 > 63 ) {
306 			yyerror("Flags must be 0..63");
307 			YYABORT;
308 		}
309 		$$.self = NewBlock(OffsetFlags, MaskFlags, ($3 << ShiftFlags) & MaskFlags, $2.comp, FUNC_NONE, NULL);
310 	}
311 
312 	| FLAGS STRING	{
313 		uint64_t fl = 0;
314 		int cnt     = 0;
315 		size_t		len = strlen($2);
316 
317 		if ( len > 7 ) {
318 			yyerror("Too many flags");
319 			YYABORT;
320 		}
321 
322 		if ( strchr($2, 'F') ) { fl |=  1; cnt++; }
323 		if ( strchr($2, 'S') ) { fl |=  2; cnt++; }
324 		if ( strchr($2, 'R') ) { fl |=  4; cnt++; }
325 		if ( strchr($2, 'P') ) { fl |=  8; cnt++; }
326 		if ( strchr($2, 'A') ) { fl |=  16; cnt++; }
327 		if ( strchr($2, 'U') ) { fl |=  32; cnt++; }
328 		if ( strchr($2, 'X') ) { fl =  63; cnt++; }
329 
330 		if ( cnt != len ) {
331 			yyerror("Too many flags");
332 			YYABORT;
333 		}
334 
335 		$$.self = NewBlock(OffsetFlags, (fl << ShiftFlags) & MaskFlags,
336 					(fl << ShiftFlags) & MaskFlags, CMP_FLAGS, FUNC_NONE, NULL);
337 	}
338 
339 	| dqual IP STRING {
340 		int af, bytes, ret;
341 
342 		ret = parse_ip(&af, $3, IPstack, &bytes, ALLOW_LOOKUP, &num_ip);
343 
344 		if ( ret == 0 ) {
345 			yyerror("Error parsing IP address.");
346 			YYABORT;
347 		}
348 
349 		// ret == -1 will never happen here, as ALLOW_LOOKUP is set
350 		if ( ret == -2 ) {
351 			// could not resolv host => 'not any'
352 			$$.self = Invert(NewBlock(OffsetProto, 0, 0, CMP_EQ, FUNC_NONE, NULL ));
353 		} else {
354 			uint64_t offsets[4] = {OffsetSrcIPv6a, OffsetSrcIPv6b, OffsetDstIPv6a, OffsetDstIPv6b };
355 			if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
356 				yyerror("incomplete IP address");
357 				YYABORT;
358 			}
359 
360 			switch ( $1.direction ) {
361 				case SOURCE:
362 				case DESTINATION:
363 					$$.self = ChainHosts(offsets, IPstack, num_ip, $1.direction);
364 					break;
365 				case DIR_UNSPEC:
366 				case SOURCE_OR_DESTINATION: {
367 					uint32_t src = ChainHosts(offsets, IPstack, num_ip, SOURCE);
368 					uint32_t dst = ChainHosts(offsets, IPstack, num_ip, DESTINATION);
369 					$$.self = Connect_OR(src, dst);
370 					} break;
371 				case SOURCE_AND_DESTINATION: {
372 					uint32_t src = ChainHosts(offsets, IPstack, num_ip, SOURCE);
373 					uint32_t dst = ChainHosts(offsets, IPstack, num_ip, DESTINATION);
374 					$$.self = Connect_AND(src, dst);
375 					} break;
376 				default:
377 					yyerror("This token is not expected here!");
378 					YYABORT;
379 
380 			} // End of switch
381 
382 		}
383 	}
384 
385 	| dqual IP IN '[' iplist ']' {
386 
387 		switch ( $1.direction ) {
388 			case SOURCE:
389 				$$.self = NewBlock(OffsetSrcIPv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 );
390 				break;
391 			case DESTINATION:
392 				$$.self = NewBlock(OffsetDstIPv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 );
393 				break;
394 			case DIR_UNSPEC:
395 			case SOURCE_OR_DESTINATION:
396 				$$.self = Connect_OR(
397 					NewBlock(OffsetSrcIPv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 ),
398 					NewBlock(OffsetDstIPv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 )
399 				);
400 				break;
401 			case SOURCE_AND_DESTINATION:
402 				$$.self = Connect_AND(
403 					NewBlock(OffsetSrcIPv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 ),
404 					NewBlock(OffsetDstIPv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 )
405 				);
406 				break;
407 			default:
408 				yyerror("This token is not expected here!");
409 				YYABORT;
410 		}
411 	}
412 
413 	| NEXT IP STRING {
414 		int af, bytes, ret;
415 
416 		ret = parse_ip(&af, $3, IPstack, &bytes, STRICT_IP, &num_ip);
417 
418 		if ( ret == 0 ) {
419 			yyerror("Error parsing IP address.");
420 			YYABORT;
421 		}
422 
423 		if ( ret == -1 ) {
424 			yyerror("IP address required - hostname not allowed here.");
425 			YYABORT;
426 		}
427 		// ret == -2 will never happen here, as STRICT_IP is set
428 
429 		if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
430 			yyerror("incomplete IP address");
431 			YYABORT;
432 		}
433 
434 		$$.self = Connect_AND(
435 			NewBlock(OffsetNexthopv6b, MaskIPv6, IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
436 			NewBlock(OffsetNexthopv6a, MaskIPv6, IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
437 		);
438 	}
439 
440 	| NEXT IP IN '[' iplist ']' {
441 
442 		$$.self = NewBlock(OffsetNexthopv6a, MaskIPv6, 0 , CMP_IPLIST, FUNC_NONE, (void *)$5 );
443 
444 	}
445 
446 	| BGPNEXTHOP IP STRING {
447 		int af, bytes, ret;
448 
449 		ret = parse_ip(&af, $3, IPstack, &bytes, STRICT_IP, &num_ip);
450 
451 		if ( ret == 0 ) {
452 			yyerror("Error parsing IP address.");
453 			YYABORT;
454 		}
455 
456 		if ( ret == -1 ) {
457 			yyerror("IP address required - hostname not allowed here.");
458 			YYABORT;
459 		}
460 		// ret == -2 will never happen here, as STRICT_IP is set
461 
462 		if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
463 			yyerror("incomplete IP address");
464 			YYABORT;
465 		}
466 
467 		$$.self = Connect_AND(
468 			NewBlock(OffsetBGPNexthopv6b, MaskIPv6, IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
469 			NewBlock(OffsetBGPNexthopv6a, MaskIPv6, IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
470 		);
471 	}
472 
473 	| ROUTER IP STRING {
474 		int af, bytes, ret;
475 
476 		ret = parse_ip(&af, $3, IPstack, &bytes, STRICT_IP, &num_ip);
477 
478 		if ( ret == 0 ) {
479 			yyerror("Error parsing IP address.");
480 			YYABORT;
481 		}
482 
483 		if ( ret == -1 ) {
484 			yyerror("IP address required - hostname not allowed here.");
485 			YYABORT;
486 		}
487 		// ret == -2 will never happen here, as STRICT_IP is set
488 
489 		if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
490 			yyerror("incomplete IP address");
491 			YYABORT;
492 		}
493 
494 		$$.self = Connect_AND(
495 			NewBlock(OffsetRouterv6b, MaskIPv6, IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
496 			NewBlock(OffsetRouterv6a, MaskIPv6, IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
497 		);
498 	}
499 
500 	| CLIENT LATENCY comp NUMBER {
501 		$$.self = NewBlock(OffsetClientLatency, MaskLatency, $4, $3.comp, FUNC_NONE, NULL);
502 	}
503 
504 	| SERVER LATENCY comp NUMBER {
505 		$$.self = NewBlock(OffsetServerLatency, MaskLatency, $4, $3.comp, FUNC_NONE, NULL);
506 	}
507 
508 	| APP LATENCY comp NUMBER {
509 		$$.self = NewBlock(OffsetAppLatency, MaskLatency, $4, $3.comp, FUNC_NONE, NULL);
510 	}
511 
512 	| SYSID NUMBER {
513 		if ( $2 > 255 ) {
514 			yyerror("Router SysID expected between be 1..255");
515 			YYABORT;
516 		}
517 		$$.self = NewBlock(OffsetExporterSysID, MaskExporterSysID, ($2 << ShiftExporterSysID) & MaskExporterSysID, CMP_EQ, FUNC_NONE, NULL);
518 	}
519 
520 	| dqual PORT comp NUMBER {
521 		if ( $4 > 65535 ) {
522 			yyerror("Port outside of range 0..65535");
523 			YYABORT;
524 		}
525 
526 		switch ( $1.direction ) {
527 			case SOURCE:
528 				$$.self = NewBlock(OffsetPort, MaskSrcPort, ($4 << ShiftSrcPort) & MaskSrcPort, $3.comp, FUNC_NONE, NULL );
529 				break;
530 			case DESTINATION:
531 				$$.self = NewBlock(OffsetPort, MaskDstPort, ($4 << ShiftDstPort) & MaskDstPort, $3.comp, FUNC_NONE, NULL );
532 				break;
533 			case DIR_UNSPEC:
534 			case SOURCE_OR_DESTINATION:
535 				$$.self = Connect_OR(
536 					NewBlock(OffsetPort, MaskSrcPort, ($4 << ShiftSrcPort) & MaskSrcPort, $3.comp, FUNC_NONE, NULL ),
537 					NewBlock(OffsetPort, MaskDstPort, ($4 << ShiftDstPort) & MaskDstPort, $3.comp, FUNC_NONE, NULL )
538 				);
539 				break;
540 			case SOURCE_AND_DESTINATION:
541 				$$.self = Connect_AND(
542 					NewBlock(OffsetPort, MaskSrcPort, ($4 << ShiftSrcPort) & MaskSrcPort, $3.comp, FUNC_NONE, NULL ),
543 					NewBlock(OffsetPort, MaskDstPort, ($4 << ShiftDstPort) & MaskDstPort, $3.comp, FUNC_NONE, NULL )
544 				);
545 				break;
546 			default:
547 				yyerror("This token is not expected here!");
548 				YYABORT;
549 		} // End switch
550 
551 	}
552 
553 	| dqual PORT IN PBLOCK {
554 #ifdef NSEL
555 		switch ( $1.direction ) {
556 			case SOURCE:
557 					$$.self = NewBlock(OffsetPort, MaskSrcPort, ShiftSrcPort, CMP_EQ, FUNC_PBLOCK, NULL );
558 				break;
559 			case DESTINATION:
560 					$$.self = NewBlock(OffsetPort, MaskDstPort, ShiftDstPort, CMP_EQ, FUNC_PBLOCK, NULL );
561 				break;
562 			case DIR_UNSPEC:
563 			case SOURCE_OR_DESTINATION:
564 				$$.self = Connect_OR(
565 					NewBlock(OffsetPort, MaskSrcPort, ShiftSrcPort, CMP_EQ, FUNC_PBLOCK, NULL ),
566 					NewBlock(OffsetPort, MaskDstPort, ShiftDstPort, CMP_EQ, FUNC_PBLOCK, NULL )
567 				);
568 				break;
569 			default:
570 				yyerror("This token is not expected here!");
571 				YYABORT;
572 		} // End switch
573 
574 #else
575 		yyerror("NAT filters not available");
576 		YYABORT;
577 #endif
578 	}
579 
580 	| dqual PORT IN '[' ullist ']' {
581 		struct ULongListNode *node;
582 		ULongtree_t *root = NULL;
583 
584 		if ( $1.direction == DIR_UNSPEC || $1.direction == SOURCE_OR_DESTINATION || $1.direction == SOURCE_AND_DESTINATION ) {
585 			// src and/or dst port
586 			// we need a second rbtree due to different shifts for src and dst ports
587 			root = malloc(sizeof(ULongtree_t));
588 
589 			struct ULongListNode *n;
590 			if ( root == NULL) {
591 				yyerror("malloc() error");
592 				YYABORT;
593 			}
594 			RB_INIT(root);
595 
596 			RB_FOREACH(node, ULongtree, (ULongtree_t *)$5) {
597 				if ( node->value > 65535 ) {
598 					yyerror("Port outside of range 0..65535");
599 					YYABORT;
600 				}
601 				if ((n = malloc(sizeof(struct ULongListNode))) == NULL) {
602 					yyerror("malloc() error");
603 					YYABORT;
604 				}
605 				n->value 	= (node->value << ShiftDstPort) & MaskDstPort;
606 				node->value = (node->value << ShiftSrcPort) & MaskSrcPort;
607 				RB_INSERT(ULongtree, root, n);
608 			}
609 		}
610 
611 		switch ( $1.direction ) {
612 			case SOURCE:
613 				RB_FOREACH(node, ULongtree, (ULongtree_t *)$5) {
614 					node->value = (node->value << ShiftSrcPort) & MaskSrcPort;
615 				}
616 				$$.self = NewBlock(OffsetPort, MaskSrcPort, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 );
617 				break;
618 			case DESTINATION:
619 				RB_FOREACH(node, ULongtree, (ULongtree_t *)$5) {
620 					node->value = (node->value << ShiftDstPort) & MaskDstPort;
621 				}
622 				$$.self = NewBlock(OffsetPort, MaskDstPort, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 );
623 				break;
624 			case DIR_UNSPEC:
625 			case SOURCE_OR_DESTINATION:
626 				$$.self = Connect_OR(
627 					NewBlock(OffsetPort, MaskSrcPort, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 ),
628 					NewBlock(OffsetPort, MaskDstPort, 0, CMP_ULLIST, FUNC_NONE, (void *)root )
629 				);
630 				break;
631 			case SOURCE_AND_DESTINATION:
632 				$$.self = Connect_AND(
633 					NewBlock(OffsetPort, MaskSrcPort, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 ),
634 					NewBlock(OffsetPort, MaskDstPort, 0, CMP_ULLIST, FUNC_NONE, (void *)root )
635 				);
636 				break;
637 			default:
638 				yyerror("This token is not expected here!");
639 				YYABORT;
640 		} // End of switch
641 
642 	}
643 
644 	| ICMP_TYPE NUMBER {
645 		if ( $2 > 255 ) {
646 			yyerror("ICMP tpye of range 0..15");
647 			YYABORT;
648 		}
649 		$$.self = Connect_AND(
650 			// imply proto ICMP with a proto ICMP block
651 			Connect_OR (
652 				NewBlock(OffsetProto, MaskProto, ((uint64_t)IPPROTO_ICMP << ShiftProto)  & MaskProto, CMP_EQ, FUNC_NONE, NULL),
653 				NewBlock(OffsetProto, MaskProto, ((uint64_t)IPPROTO_ICMPV6 << ShiftProto)  & MaskProto, CMP_EQ, FUNC_NONE, NULL)
654 			),
655 			NewBlock(OffsetPort, MaskICMPtype, ($2 << ShiftICMPtype) & MaskICMPtype, CMP_EQ, FUNC_NONE, NULL )
656 		);
657 
658 	}
659 
660 	| ICMP_CODE NUMBER {
661 		if ( $2 > 255 ) {
662 			yyerror("ICMP code of range 0..15");
663 			YYABORT;
664 		}
665 		$$.self = Connect_AND(
666 			// imply proto ICMP with a proto ICMP block
667 			Connect_OR (
668 				NewBlock(OffsetProto, MaskProto, ((uint64_t)IPPROTO_ICMP << ShiftProto)  & MaskProto, CMP_EQ, FUNC_NONE, NULL),
669 				NewBlock(OffsetProto, MaskProto, ((uint64_t)IPPROTO_ICMPV6 << ShiftProto)  & MaskProto, CMP_EQ, FUNC_NONE, NULL)
670 			),
671 			NewBlock(OffsetPort, MaskICMPcode, ($2 << ShiftICMPcode) & MaskICMPcode, CMP_EQ, FUNC_NONE, NULL )
672 		);
673 
674 	}
675 
676 	| ENGINE_TYPE comp NUMBER {
677 		if ( $3 > 255 ) {
678 			yyerror("Engine type of range 0..255");
679 			YYABORT;
680 		}
681 		$$.self = NewBlock(OffsetRouterID, MaskEngineType, ($3 << ShiftEngineType) & MaskEngineType, $2.comp, FUNC_NONE, NULL);
682 
683 	}
684 
685 	| ENGINE_ID comp NUMBER {
686 		if ( $3 > 255 ) {
687 			yyerror("Engine ID of range 0..255");
688 			YYABORT;
689 		}
690 		$$.self = NewBlock(OffsetRouterID, MaskEngineID, ($3 << ShiftEngineID) & MaskEngineID, $2.comp, FUNC_NONE, NULL);
691 
692 	}
693 
694 	| ASA EVENT REASON {
695 #ifdef NSEL
696 		if ( strncasecmp($3,"ignore", 6) == 0) {
697 			$$.self = NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_IGNORE << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL );
698 		} else if( strncasecmp($3,"create", 6) == 0) {
699 			$$.self = NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_CREATE << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL );
700 		} else if( strncasecmp($3,"term", 4) == 0 || strncasecmp($3,"delete", 6) == 0) {
701 			$$.self = NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_DELETE << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL );
702 		} else if  (strncasecmp($3,"deny", 4) == 0) {
703 			$$.self = NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_DENIED << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL );
704 		} else if  (strncasecmp($3,"alert", 5) == 0) {
705 			$$.self = NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_ALERT << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL );
706 		} else if  (strncasecmp($3,"update", 6) == 0) {
707 			$$.self = NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_UPDATE << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL );
708 		} else {
709 			yyerror("Unknown asa event");
710 			YYABORT;
711 		}
712 #else
713 		yyerror("NSEL/ASA filters not available");
714 		YYABORT;
715 #endif
716 	}
717 
718 	| ASA EVENT comp NUMBER {
719 #ifdef NSEL
720 		if ( $4 > 255 ) {
721 			yyerror("Invalid xevent ID");
722 			YYABORT;
723 		}
724 		$$.self = NewBlock(OffsetConnID, MaskFWevent, ( $4 << ShiftFWevent) & MaskFWevent, $3.comp, FUNC_NONE, NULL );
725 #else
726 		yyerror("NSEL/ASA filters not available");
727 		YYABORT;
728 #endif
729 	}
730 
731 	| ASA EVENT DENIED inout {
732 #ifdef NSEL
733 		uint64_t xevent = 0;
734 		if ( $4.inout == INGRESS ) {
735 			xevent = 1001;
736 		} else if ( $4.inout == EGRESS ) {
737 			xevent = 1002;
738 		} else {
739 				yyerror("Invalid inout token");
740 				YYABORT;
741 		}
742 		$$.self = Connect_AND(
743 			NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_DENIED << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL ),
744 			NewBlock(OffsetConnID, MaskFWXevent, ( xevent << ShiftFWXevent) & MaskFWXevent, CMP_EQ, FUNC_NONE, NULL )
745 		);
746 #else
747 		yyerror("NSEL/ASA filters not available");
748 		YYABORT;
749 #endif
750 	}
751 	| ASA EVENT DENIED STRING {
752 #ifdef NSEL
753 		uint64_t xevent = 0;
754 		if( strncasecmp($4,"interface", 9) == 0) {
755 			xevent = 1003;
756 		} else if( strncasecmp($4,"nosyn", 5) == 0) {
757 			xevent = 1004;
758 		} else {
759 			xevent = (uint64_t)strtol($4, (char **)NULL, 10);
760 			if ( (xevent == 0 && errno == EINVAL) || xevent > 65535 ) {
761 				yyerror("Invalid xevent ID");
762 				YYABORT;
763 			}
764 		}
765 		$$.self = Connect_AND(
766 			NewBlock(OffsetConnID, MaskFWevent, ( NSEL_EVENT_DENIED << ShiftFWevent) & MaskFWevent, CMP_EQ, FUNC_NONE, NULL ),
767 			NewBlock(OffsetConnID, MaskFWXevent, ( xevent << ShiftFWXevent) & MaskFWXevent, CMP_EQ, FUNC_NONE, NULL )
768 		);
769 #else
770 		yyerror("NSEL/ASA filters not available");
771 		YYABORT;
772 #endif
773 	}
774 
775 	| ASA XEVENT comp NUMBER {
776 #ifdef NSEL
777 		if ( $4 > 65535 ) {
778 			yyerror("Invalid xevent ID");
779 			YYABORT;
780 		}
781 		$$.self = NewBlock(OffsetConnID, MaskFWXevent, ( $4 << ShiftFWXevent) & MaskFWXevent, $3.comp, FUNC_NONE, NULL );
782 #else
783 		yyerror("NSEL/ASA filters not available");
784 		YYABORT;
785 #endif
786 	}
787 
788 	| dqual XIP STRING {
789 #ifdef NSEL
790 		int af, bytes, ret;
791 
792 		ret = parse_ip(&af, $3, IPstack, &bytes, ALLOW_LOOKUP, &num_ip);
793 
794 		if ( ret == 0 ) {
795 			yyerror("Error parsing IP address.");
796 			YYABORT;
797 		}
798 
799 		// ret == -1 will never happen here, as ALLOW_LOOKUP is set
800 		if ( ret == -2 ) {
801 			// could not resolv host => 'not any'
802 			$$.self = Invert(NewBlock(OffsetProto, 0, 0, CMP_EQ, FUNC_NONE, NULL ));
803 		} else {
804 			uint64_t offsets[4] = {OffsetXLATESRCv6a, OffsetXLATESRCv6b, OffsetXLATEDSTv6a, OffsetXLATEDSTv6b };
805 			if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
806 				yyerror("incomplete IP address");
807 				YYABORT;
808 			}
809 
810 			switch ( $1.direction ) {
811 				case SOURCE:
812 				case DESTINATION:
813 					$$.self = ChainHosts(offsets, IPstack, num_ip, $1.direction);
814 					break;
815 				case DIR_UNSPEC:
816 				case SOURCE_OR_DESTINATION: {
817 					uint32_t src = ChainHosts(offsets, IPstack, num_ip, SOURCE);
818 					uint32_t dst = ChainHosts(offsets, IPstack, num_ip, DESTINATION);
819 					$$.self = Connect_OR(src, dst);
820 					} break;
821 				case SOURCE_AND_DESTINATION: {
822 					uint32_t src = ChainHosts(offsets, IPstack, num_ip, SOURCE);
823 					uint32_t dst = ChainHosts(offsets, IPstack, num_ip, DESTINATION);
824 					$$.self = Connect_AND(src, dst);
825 					} break;
826 				default:
827 					yyerror("This token is not expected here!");
828 					YYABORT;
829 
830 			} // End of switch
831 
832 		}
833 #else
834 		yyerror("NSEL/ASA filters not available");
835 		YYABORT;
836 #endif
837 	}
838 
839 	| dqual XNET STRING '/' NUMBER {
840 #ifdef NSEL
841 		int af, bytes, ret;
842 		uint64_t	mask[2];
843 
844 		ret = parse_ip(&af, $3, IPstack, &bytes, STRICT_IP, &num_ip);
845 		if ( ret == 0 ) {
846 			yyerror("Invalid IP address");
847 			YYABORT;
848 		}
849 		if ( ret == -1 ) {
850 			yyerror("IP address required - hostname not allowed here.");
851 			YYABORT;
852 		}
853 		// ret == -2 will never happen here, as STRICT_IP is set
854 
855 
856 		if ( $5 > (bytes*8) ) {
857 			yyerror("Too many netbits for this IP address");
858 			YYABORT;
859 		}
860 
861 		if ( af == PF_INET ) {
862 			mask[0] = 0xffffffffffffffffLL;
863 			mask[1] = 0xffffffffffffffffLL << ( 32 - $5 );
864 		} else {	// PF_INET6
865 			if ( $5 > 64 ) {
866 				mask[0] = 0xffffffffffffffffLL;
867 				mask[1] = 0xffffffffffffffffLL << ( 128 - $5 );
868 			} else {
869 				mask[0] = 0xffffffffffffffffLL << ( 64 - $5 );
870 				mask[1] = 0;
871 			}
872 		}
873 		// IP aadresses are stored in network representation
874 		mask[0]	 = mask[0];
875 		mask[1]	 = mask[1];
876 
877 		IPstack[0] &= mask[0];
878 		IPstack[1] &= mask[1];
879 
880 		switch ( $1.direction ) {
881 			case SOURCE:
882 				$$.self = Connect_AND(
883 					NewBlock(OffsetXLATESRCv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
884 					NewBlock(OffsetXLATESRCv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
885 				);
886 				break;
887 			case DESTINATION:
888 				$$.self = Connect_AND(
889 					NewBlock(OffsetXLATEDSTv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
890 					NewBlock(OffsetXLATEDSTv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
891 				);
892 				break;
893 			case DIR_UNSPEC:
894 			case SOURCE_OR_DESTINATION:
895 				$$.self = Connect_OR(
896 					Connect_AND(
897 						NewBlock(OffsetXLATESRCv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
898 						NewBlock(OffsetXLATESRCv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
899 					),
900 					Connect_AND(
901 						NewBlock(OffsetXLATEDSTv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
902 						NewBlock(OffsetXLATEDSTv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
903 					)
904 				);
905 				break;
906 			case SOURCE_AND_DESTINATION:
907 				$$.self = Connect_AND(
908 					Connect_AND(
909 						NewBlock(OffsetXLATESRCv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
910 						NewBlock(OffsetXLATESRCv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
911 					),
912 					Connect_AND(
913 						NewBlock(OffsetXLATEDSTv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
914 						NewBlock(OffsetXLATEDSTv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
915 					)
916 				);
917 				break;
918 			default:
919 				yyerror("This token is not expected here!");
920 				YYABORT;
921 		} // End of switch
922 
923 #else
924 		yyerror("NSEL/ASA filters not available");
925 		YYABORT;
926 #endif
927 	}
928 
929 	| dqual XPORT comp NUMBER {
930 #ifdef NSEL
931 		if ( $4 > 65535 ) {
932 			yyerror("Port outside of range 0..65535");
933 			YYABORT;
934 		}
935 
936 		switch ( $1.direction ) {
937 			case SOURCE:
938 				$$.self = NewBlock(OffsetXLATEPort, MaskXLATESRCPORT, ($4 << ShiftXLATESRCPORT) & MaskXLATESRCPORT, $3.comp, FUNC_NONE, NULL );
939 				break;
940 			case DESTINATION:
941 				$$.self = NewBlock(OffsetXLATEPort, MaskXLATEDSTPORT, ($4 << ShiftXLATEDSTPORT) & MaskXLATEDSTPORT, $3.comp, FUNC_NONE, NULL );
942 				break;
943 			case DIR_UNSPEC:
944 			case SOURCE_OR_DESTINATION:
945 				$$.self = Connect_OR(
946 					NewBlock(OffsetXLATEPort, MaskXLATESRCPORT, ($4 << ShiftXLATESRCPORT) & MaskXLATESRCPORT, $3.comp, FUNC_NONE, NULL ),
947 					NewBlock(OffsetXLATEPort, MaskXLATEDSTPORT, ($4 << ShiftXLATEDSTPORT) & MaskXLATEDSTPORT, $3.comp, FUNC_NONE, NULL )
948 				);
949 				break;
950 			case SOURCE_AND_DESTINATION:
951 				$$.self = Connect_AND(
952 					NewBlock(OffsetXLATEPort, MaskXLATESRCPORT, ($4 << ShiftXLATESRCPORT) & MaskXLATESRCPORT, $3.comp, FUNC_NONE, NULL ),
953 					NewBlock(OffsetXLATEPort, MaskXLATEDSTPORT, ($4 << ShiftXLATEDSTPORT) & MaskXLATEDSTPORT, $3.comp, FUNC_NONE, NULL )
954 				);
955 				break;
956 			default:
957 				yyerror("This token is not expected here!");
958 				YYABORT;
959 		} // End switch
960 #else
961 		yyerror("NSEL/ASA filters not available");
962 		YYABORT;
963 #endif
964 
965 	}
966 
967 	| inout acl comp NUMBER {
968 #ifdef NSEL
969 		uint64_t offset, mask, shift;
970 		if ( $1.inout == INGRESS ) {
971 			switch ($2.acl) {
972 				case ACL:
973 					offset = OffsetIngressAclId;
974 					mask   = MaskIngressAclId;
975 					shift  = ShiftIngressAclId;
976 					break;
977 				case ACE:
978 					offset = OffsetIngressAceId;
979 					mask   = MaskIngressAceId;
980 					shift  = ShiftIngressAceId;
981 					break;
982 				case XACE:
983 					offset = OffsetIngressGrpId;
984 					mask   = MaskIngressGrpId;
985 					shift  = ShiftIngressGrpId;
986 					break;
987 				default:
988 					yyerror("Invalid ACL specifier");
989 					YYABORT;
990 			}
991 		} else if ( $1.inout == EGRESS && $$.acl == ACL ) {
992 			offset = OffsetEgressAclId;
993 			mask   = MaskEgressAclId;
994 			shift  = ShiftEgressAclId;
995 		} else {
996 			yyerror("ingress/egress syntax error");
997 			YYABORT;
998 		}
999 		$$.self = NewBlock(offset, mask, ($4 << shift) & mask , $3.comp, FUNC_NONE, NULL );
1000 
1001 #else
1002 		yyerror("NSEL/ASA filters not available");
1003 		YYABORT;
1004 #endif
1005 	}
1006 
1007 	| NAT EVENT REASON {
1008 #ifdef NSEL
1009 		if ( strncasecmp($3,"invalid", 7) == 0) {
1010 			$$.self = NewBlock(OffsetNATevent, MasNATevent, ( NEL_EVENT_INVALID << ShiftNATevent) & MasNATevent, CMP_EQ, FUNC_NONE, NULL );
1011 		} else if( strncasecmp($3,"add", 3) == 0 || strncasecmp($3,"create", 6) == 0) {
1012 			$$.self = NewBlock(OffsetNATevent, MasNATevent, ( NEL_EVENT_ADD << ShiftNATevent) & MasNATevent, CMP_EQ, FUNC_NONE, NULL );
1013 		} else if( strncasecmp($3,"delete", 6) == 0) {
1014 			$$.self = NewBlock(OffsetNATevent, MasNATevent, ( NEL_EVENT_DELETE << ShiftNATevent) & MasNATevent, CMP_EQ, FUNC_NONE, NULL );
1015 		} else {
1016 			yyerror("Unknown nat event");
1017 			YYABORT;
1018 		}
1019 #else
1020 		yyerror("NAT filters not available");
1021 		YYABORT;
1022 #endif
1023 	}
1024 
1025 	| NAT EVENT comp NUMBER {
1026 #ifdef NSEL
1027 		if ( $4 > 255 ) {
1028 			yyerror("Invalid event ID");
1029 			YYABORT;
1030 		}
1031 		$$.self = NewBlock(OffsetNATevent, MasNATevent, ( $4 << ShiftNATevent) & MasNATevent, $3.comp, FUNC_NONE, NULL );
1032 #else
1033 		yyerror("NAT filters not available");
1034 		YYABORT;
1035 #endif
1036 	}
1037 
1038 	| INGRESS VRF comp NUMBER {
1039 #ifdef NSEL
1040 		if ( $4 > 0xFFFFFFFFLL ) {
1041 			yyerror("Invalid ingress vrf ID");
1042 			YYABORT;
1043 		}
1044 		$$.self = NewBlock(OffsetIVRFID, MaskIVRFID, ( $4 << ShiftIVRFID) & MaskIVRFID, $3.comp, FUNC_NONE, NULL );
1045 #else
1046 		yyerror("NAT filters not available");
1047 		YYABORT;
1048 #endif
1049 	}
1050 
1051 	| EGRESS VRF comp NUMBER {
1052 #ifdef NSEL
1053 		if ( $4 > 0xFFFFFFFFLL ) {
1054 			yyerror("Invalid egress vrf ID");
1055 			YYABORT;
1056 		}
1057 		$$.self = NewBlock(OffsetEVRFID, MaskEVRFID, ( $4 << ShiftEVRFID) & MaskEVRFID, $3.comp, FUNC_NONE, NULL );
1058 #else
1059 		yyerror("NAT filters not available");
1060 		YYABORT;
1061 #endif
1062 	}
1063 
1064 	| PBLOCK START comp NUMBER {
1065 #ifdef NSEL
1066 		if ( $4 > 65536 ) {
1067 			yyerror("Invalid port");
1068 			YYABORT;
1069 		}
1070 		$$.self = NewBlock(OffsetPortBlock, MaskPortBlockStart, ( $4 << ShiftPortBlockStart) & MaskPortBlockStart, $3.comp, FUNC_NONE, NULL );
1071 #else
1072 		yyerror("NAT filters not available");
1073 		YYABORT;
1074 #endif
1075 	}
1076 
1077 	| PBLOCK END comp NUMBER {
1078 #ifdef NSEL
1079 		if ( $4 > 65536 ) {
1080 			yyerror("Invalid port");
1081 			YYABORT;
1082 		}
1083 		$$.self = NewBlock(OffsetPortBlock, MaskPortBlockEnd, ( $4 << ShiftPortBlockEnd) & MaskPortBlockEnd, $3.comp, FUNC_NONE, NULL );
1084 #else
1085 		yyerror("NAT filters not available");
1086 		YYABORT;
1087 #endif
1088 	}
1089 
1090 	| PBLOCK STEP comp NUMBER {
1091 #ifdef NSEL
1092 		if ( $4 > 65536 ) {
1093 			yyerror("Invalid port");
1094 			YYABORT;
1095 		}
1096 		$$.self = NewBlock(OffsetPortBlock, MaskPortBlockStep, ( $4 << ShiftPortBlockStep) & MaskPortBlockStep, $3.comp, FUNC_NONE, NULL );
1097 #else
1098 		yyerror("NAT filters not available");
1099 		YYABORT;
1100 #endif
1101 	}
1102 
1103 	| PBLOCK SIZE comp NUMBER {
1104 #ifdef NSEL
1105 		if ( $4 > 65536 ) {
1106 			yyerror("Invalid port");
1107 			YYABORT;
1108 		}
1109 		$$.self = NewBlock(OffsetPortBlock, MaskPortBlockSize, ( $4 << ShiftPortBlockSize) & MaskPortBlockSize, $3.comp, FUNC_NONE, NULL );
1110 #else
1111 		yyerror("NAT filters not available");
1112 		YYABORT;
1113 #endif
1114 	}
1115 
1116 	| dqual NPORT comp NUMBER {
1117 #ifdef NSEL
1118 		if ( $4 > 65535 ) {
1119 			yyerror("Port outside of range 0..65535");
1120 			YYABORT;
1121 		}
1122 
1123 		switch ( $1.direction ) {
1124 			case SOURCE:
1125 				$$.self = NewBlock(OffsetXLATEPort, MaskXLATESRCPORT, ($4 << ShiftXLATESRCPORT) & MaskXLATESRCPORT, $3.comp, FUNC_NONE, NULL );
1126 				break;
1127 			case DESTINATION:
1128 				$$.self = NewBlock(OffsetXLATEPort, MaskXLATEDSTPORT, ($4 << ShiftXLATEDSTPORT) & MaskXLATEDSTPORT, $3.comp, FUNC_NONE, NULL );
1129 				break;
1130 			case DIR_UNSPEC:
1131 			case SOURCE_OR_DESTINATION:
1132 				$$.self = Connect_OR(
1133 					NewBlock(OffsetXLATEPort, MaskXLATESRCPORT, ($4 << ShiftXLATESRCPORT) & MaskXLATESRCPORT, $3.comp, FUNC_NONE, NULL ),
1134 					NewBlock(OffsetXLATEPort, MaskXLATEDSTPORT, ($4 << ShiftXLATEDSTPORT) & MaskXLATEDSTPORT, $3.comp, FUNC_NONE, NULL )
1135 				);
1136 				break;
1137 			case SOURCE_AND_DESTINATION:
1138 				$$.self = Connect_AND(
1139 					NewBlock(OffsetXLATEPort, MaskXLATESRCPORT, ($4 << ShiftXLATESRCPORT) & MaskXLATESRCPORT, $3.comp, FUNC_NONE, NULL ),
1140 					NewBlock(OffsetXLATEPort, MaskXLATEDSTPORT, ($4 << ShiftXLATEDSTPORT) & MaskXLATEDSTPORT, $3.comp, FUNC_NONE, NULL )
1141 				);
1142 				break;
1143 			default:
1144 				yyerror("This token is not expected here!");
1145 				YYABORT;
1146 		} // End switch
1147 #else
1148 		yyerror("NEL/NAT filters not available");
1149 		YYABORT;
1150 #endif
1151 
1152 	}
1153 
1154 	| dqual NIP STRING {
1155 #ifdef NSEL
1156 		int af, bytes, ret;
1157 
1158 		ret = parse_ip(&af, $3, IPstack, &bytes, ALLOW_LOOKUP, &num_ip);
1159 
1160 		if ( ret == 0 ) {
1161 			yyerror("Error parsing IP address.");
1162 			YYABORT;
1163 		}
1164 
1165 		// ret == -1 will never happen here, as ALLOW_LOOKUP is set
1166 		if ( ret == -2 ) {
1167 			// could not resolv host => 'not any'
1168 			$$.self = Invert(NewBlock(OffsetProto, 0, 0, CMP_EQ, FUNC_NONE, NULL ));
1169 		} else {
1170 			uint64_t offsets[4] = {OffsetXLATESRCv6a, OffsetXLATESRCv6b, OffsetXLATEDSTv6a, OffsetXLATEDSTv6b };
1171 			if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
1172 				yyerror("incomplete IP address");
1173 				YYABORT;
1174 			}
1175 
1176 			switch ( $1.direction ) {
1177 				case SOURCE:
1178 				case DESTINATION:
1179 					$$.self = ChainHosts(offsets, IPstack, num_ip, $1.direction);
1180 					break;
1181 				case DIR_UNSPEC:
1182 				case SOURCE_OR_DESTINATION: {
1183 					uint32_t src = ChainHosts(offsets, IPstack, num_ip, SOURCE);
1184 					uint32_t dst = ChainHosts(offsets, IPstack, num_ip, DESTINATION);
1185 					$$.self = Connect_OR(src, dst);
1186 					} break;
1187 				case SOURCE_AND_DESTINATION: {
1188 					uint32_t src = ChainHosts(offsets, IPstack, num_ip, SOURCE);
1189 					uint32_t dst = ChainHosts(offsets, IPstack, num_ip, DESTINATION);
1190 					$$.self = Connect_AND(src, dst);
1191 					} break;
1192 				default:
1193 					yyerror("This token is not expected here!");
1194 					YYABORT;
1195 
1196 			} // End of switch
1197 
1198 		}
1199 #else
1200 		yyerror("NSEL/ASA filters not available");
1201 		YYABORT;
1202 #endif
1203 	}
1204 
1205 	| dqual AS comp NUMBER {
1206 		if ( $4 > 0xfFFFFFFF ) {
1207 			yyerror("AS number of range");
1208 			YYABORT;
1209 		}
1210 
1211 		switch ( $1.direction ) {
1212 			case SOURCE:
1213 				$$.self = NewBlock(OffsetAS, MaskSrcAS, ($4 << ShiftSrcAS) & MaskSrcAS, $3.comp, FUNC_NONE, NULL );
1214 				break;
1215 			case DESTINATION:
1216 				$$.self = NewBlock(OffsetAS, MaskDstAS, ($4 << ShiftDstAS) & MaskDstAS, $3.comp, FUNC_NONE, NULL);
1217 				break;
1218 			case DIR_UNSPEC:
1219 			case SOURCE_OR_DESTINATION:
1220 				$$.self = Connect_OR(
1221 					NewBlock(OffsetAS, MaskSrcAS, ($4 << ShiftSrcAS) & MaskSrcAS, $3.comp, FUNC_NONE, NULL ),
1222 					NewBlock(OffsetAS, MaskDstAS, ($4 << ShiftDstAS) & MaskDstAS, $3.comp, FUNC_NONE, NULL)
1223 				);
1224 				break;
1225 			case SOURCE_AND_DESTINATION:
1226 				$$.self = Connect_AND(
1227 					NewBlock(OffsetAS, MaskSrcAS, ($4 << ShiftSrcAS) & MaskSrcAS, $3.comp, FUNC_NONE, NULL ),
1228 					NewBlock(OffsetAS, MaskDstAS, ($4 << ShiftDstAS) & MaskDstAS, $3.comp, FUNC_NONE, NULL)
1229 				);
1230 				break;
1231 			case ADJ_PREV:
1232 				$$.self = NewBlock(OffsetBGPadj, MaskBGPadjPrev, ($4 << ShiftBGPadjPrev) & MaskBGPadjPrev, $3.comp, FUNC_NONE, NULL );
1233 				break;
1234 			case ADJ_NEXT:
1235 				$$.self = NewBlock(OffsetBGPadj, MaskBGPadjNext, ($4 << ShiftBGPadjNext) & MaskBGPadjNext, $3.comp, FUNC_NONE, NULL );
1236 				break;
1237 			default:
1238 				yyerror("This token is not expected here!");
1239 				YYABORT;
1240 		} // End of switch
1241 
1242 	}
1243 
1244 	| dqual AS IN '[' ullist ']' {
1245 		struct ULongListNode *node;
1246 		ULongtree_t *root = NULL;
1247 
1248 		if ( $1.direction == DIR_UNSPEC || $1.direction == SOURCE_OR_DESTINATION || $1.direction == SOURCE_AND_DESTINATION ) {
1249 			// src and/or dst AS
1250 			// we need a second rbtree due to different shifts for src and dst AS
1251 			root = malloc(sizeof(ULongtree_t));
1252 
1253 			struct ULongListNode *n;
1254 			if ( root == NULL) {
1255 				yyerror("malloc() error");
1256 				YYABORT;
1257 			}
1258 			RB_INIT(root);
1259 
1260 			RB_FOREACH(node, ULongtree, (ULongtree_t *)$5) {
1261 				if ( node->value > 0xFFFFFFFFLL ) {
1262 					yyerror("AS number of range");
1263 					YYABORT;
1264 				}
1265 				if ((n = malloc(sizeof(struct ULongListNode))) == NULL) {
1266 					yyerror("malloc() error");
1267 					YYABORT;
1268 				}
1269 				n->value 	= (node->value << ShiftDstAS) & MaskDstAS;
1270 				node->value = (node->value << ShiftSrcAS) & MaskSrcAS;
1271 				RB_INSERT(ULongtree, root, n);
1272 			}
1273 		}
1274 
1275 		switch ( $1.direction ) {
1276 			case SOURCE:
1277 				RB_FOREACH(node, ULongtree, (ULongtree_t *)$5) {
1278 					node->value = (node->value << ShiftSrcAS) & MaskSrcAS;
1279 				}
1280 				$$.self = NewBlock(OffsetAS, MaskSrcAS, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 );
1281 				break;
1282 			case DESTINATION:
1283 				RB_FOREACH(node, ULongtree, (ULongtree_t *)$5) {
1284 					node->value = (node->value << ShiftDstAS) & MaskDstAS;
1285 				}
1286 				$$.self = NewBlock(OffsetAS, MaskDstAS, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 );
1287 				break;
1288 			case DIR_UNSPEC:
1289 			case SOURCE_OR_DESTINATION:
1290 				$$.self = Connect_OR(
1291 					NewBlock(OffsetAS, MaskSrcAS, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 ),
1292 					NewBlock(OffsetAS, MaskDstAS, 0, CMP_ULLIST, FUNC_NONE, (void *)root )
1293 				);
1294 				break;
1295 			case SOURCE_AND_DESTINATION:
1296 				$$.self = Connect_AND(
1297 					NewBlock(OffsetAS, MaskSrcAS, 0, CMP_ULLIST, FUNC_NONE, (void *)$5 ),
1298 					NewBlock(OffsetAS, MaskDstAS, 0, CMP_ULLIST, FUNC_NONE, (void *)root )
1299 				);
1300 				break;
1301 			default:
1302 				yyerror("This token is not expected here!");
1303 				YYABORT;
1304 		}
1305 
1306 	}
1307 
1308 	| dqual MASK NUMBER {
1309 		if ( $3 > 255 ) {
1310 			yyerror("Mask outside of range 0..255");
1311 			YYABORT;
1312 		}
1313 
1314 		switch ( $1.direction ) {
1315 			case SOURCE:
1316 				$$.self = NewBlock(OffsetMask, MaskSrcMask, ($3 << ShiftSrcMask) & MaskSrcMask, CMP_EQ, FUNC_NONE, NULL );
1317 				break;
1318 			case DESTINATION:
1319 				$$.self = NewBlock(OffsetMask, MaskDstMask, ($3 << ShiftDstMask) & MaskDstMask, CMP_EQ, FUNC_NONE, NULL );
1320 				break;
1321 			case DIR_UNSPEC:
1322 			case SOURCE_OR_DESTINATION:
1323 				$$.self = Connect_OR(
1324 					NewBlock(OffsetMask, MaskSrcMask, ($3 << ShiftSrcMask) & MaskSrcMask, CMP_EQ, FUNC_NONE, NULL ),
1325 					NewBlock(OffsetMask, MaskDstMask, ($3 << ShiftDstMask) & MaskDstMask, CMP_EQ, FUNC_NONE, NULL )
1326 				);
1327 				break;
1328 			case SOURCE_AND_DESTINATION:
1329 				$$.self = Connect_AND(
1330 					NewBlock(OffsetMask, MaskSrcMask, ($3 << ShiftSrcMask) & MaskSrcMask, CMP_EQ, FUNC_NONE, NULL ),
1331 					NewBlock(OffsetMask, MaskDstMask, ($3 << ShiftDstMask) & MaskDstMask, CMP_EQ, FUNC_NONE, NULL )
1332 				);
1333 				break;
1334 			default:
1335 				yyerror("This token is not expected here!");
1336 				YYABORT;
1337 		} // End switch
1338 
1339 	}
1340 
1341 	| dqual NET STRING STRING {
1342 		int af, bytes, ret;
1343 		uint64_t	mask[2];
1344 		ret = parse_ip(&af, $3, IPstack, &bytes, STRICT_IP, &num_ip);
1345 
1346 		if ( ret == 0 ) {
1347 			yyerror("Invalid IP address");
1348 			YYABORT;
1349 		}
1350 
1351 		if ( ret == -1 ) {
1352 			yyerror("IP address required - hostname not allowed here.");
1353 			YYABORT;
1354 		}
1355 		// ret == -2 will never happen here, as STRICT_IP is set
1356 
1357 		if ( af != PF_INET ) {
1358 			yyerror("IP netmask syntax valid only for IPv4");
1359 			YYABORT;
1360 		}
1361 		if ( bytes != 4 ) {
1362 			yyerror("Need complete IP address");
1363 			YYABORT;
1364 		}
1365 
1366 		ret = parse_ip(&af, $4, mask, &bytes, STRICT_IP, &num_ip);
1367 		if ( ret == 0 ) {
1368 			yyerror("Invalid IP address");
1369 			YYABORT;
1370 		}
1371 		if ( ret == -1 ) {
1372 			yyerror("IP address required - hostname not allowed here.");
1373 			YYABORT;
1374 		}
1375 		// ret == -2 will never happen here, as STRICT_IP is set
1376 
1377 		if ( af != PF_INET || bytes != 4 ) {
1378 			yyerror("Invalid netmask for IPv4 address");
1379 			YYABORT;
1380 		}
1381 
1382 		IPstack[0] &= mask[0];
1383 		IPstack[1] &= mask[1];
1384 
1385 		switch ( $1.direction ) {
1386 			case SOURCE:
1387 				$$.self = Connect_AND(
1388 					NewBlock(OffsetSrcIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1389 					NewBlock(OffsetSrcIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1390 				);
1391 				break;
1392 			case DESTINATION:
1393 				$$.self = Connect_AND(
1394 					NewBlock(OffsetDstIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1395 					NewBlock(OffsetDstIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1396 				);
1397 				break;
1398 			case DIR_UNSPEC:
1399 			case SOURCE_OR_DESTINATION:
1400 				$$.self = Connect_OR(
1401 					Connect_AND(
1402 						NewBlock(OffsetSrcIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1403 						NewBlock(OffsetSrcIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1404 					),
1405 					Connect_AND(
1406 						NewBlock(OffsetDstIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1407 						NewBlock(OffsetDstIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1408 					)
1409 				);
1410 				break;
1411 			case SOURCE_AND_DESTINATION:
1412 				$$.self = Connect_AND(
1413 					Connect_AND(
1414 						NewBlock(OffsetSrcIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1415 						NewBlock(OffsetSrcIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1416 					),
1417 					Connect_AND(
1418 						NewBlock(OffsetDstIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1419 						NewBlock(OffsetDstIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1420 					)
1421 				);
1422 				break;
1423 			default:
1424 				/* should never happen */
1425 				yyerror("This token is not expected here!");
1426 				YYABORT;
1427 		} // End of switch
1428 
1429 	}
1430 
1431 	| dqual NET STRING '/' NUMBER {
1432 		int af, bytes, ret;
1433 		uint64_t	mask[2];
1434 
1435 		ret = parse_ip(&af, $3, IPstack, &bytes, STRICT_IP, &num_ip);
1436 		if ( ret == 0 ) {
1437 			yyerror("Invalid IP address");
1438 			YYABORT;
1439 		}
1440 		if ( ret == -1 ) {
1441 			yyerror("IP address required - hostname not allowed here.");
1442 			YYABORT;
1443 		}
1444 		// ret == -2 will never happen here, as STRICT_IP is set
1445 
1446 
1447 		if ( $5 > (bytes*8) ) {
1448 			yyerror("Too many netbits for this IP address");
1449 			YYABORT;
1450 		}
1451 
1452 		if ( af == PF_INET ) {
1453 			mask[0] = 0xffffffffffffffffLL;
1454 			mask[1] = 0xffffffffffffffffLL << ( 32 - $5 );
1455 		} else {	// PF_INET6
1456 			if ( $5 > 64 ) {
1457 				mask[0] = 0xffffffffffffffffLL;
1458 				mask[1] = 0xffffffffffffffffLL << ( 128 - $5 );
1459 			} else {
1460 				mask[0] = 0xffffffffffffffffLL << ( 64 - $5 );
1461 				mask[1] = 0;
1462 			}
1463 		}
1464 		// IP aadresses are stored in network representation
1465 		mask[0]	 = mask[0];
1466 		mask[1]	 = mask[1];
1467 
1468 		IPstack[0] &= mask[0];
1469 		IPstack[1] &= mask[1];
1470 
1471 		switch ( $1.direction ) {
1472 			case SOURCE:
1473 				$$.self = Connect_AND(
1474 					NewBlock(OffsetSrcIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1475 					NewBlock(OffsetSrcIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1476 				);
1477 				break;
1478 			case DESTINATION:
1479 				$$.self = Connect_AND(
1480 					NewBlock(OffsetDstIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1481 					NewBlock(OffsetDstIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1482 				);
1483 				break;
1484 			case DIR_UNSPEC:
1485 			case SOURCE_OR_DESTINATION:
1486 				$$.self = Connect_OR(
1487 					Connect_AND(
1488 						NewBlock(OffsetSrcIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1489 						NewBlock(OffsetSrcIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1490 					),
1491 					Connect_AND(
1492 						NewBlock(OffsetDstIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1493 						NewBlock(OffsetDstIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1494 					)
1495 				);
1496 				break;
1497 			case SOURCE_AND_DESTINATION:
1498 				$$.self = Connect_AND(
1499 					Connect_AND(
1500 						NewBlock(OffsetSrcIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1501 						NewBlock(OffsetSrcIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1502 					),
1503 					Connect_AND(
1504 						NewBlock(OffsetDstIPv6b, mask[1], IPstack[1] , CMP_EQ, FUNC_NONE, NULL ),
1505 						NewBlock(OffsetDstIPv6a, mask[0], IPstack[0] , CMP_EQ, FUNC_NONE, NULL )
1506 					)
1507 				);
1508 				break;
1509 			default:
1510 				yyerror("This token is not expected here!");
1511 				YYABORT;
1512 		} // End of switch
1513 
1514 	}
1515 
1516 	| dqual IF NUMBER {
1517 		if ( $3 > 0xffffffffLL ) {
1518 			yyerror("Input interface number must 0..2^32");
1519 			YYABORT;
1520 		}
1521 
1522 		switch ( $1.direction ) {
1523 			case DIR_UNSPEC:
1524 				$$.self = Connect_OR(
1525 					NewBlock(OffsetInOut, MaskInput, ($3 << ShiftInput) & MaskInput, CMP_EQ, FUNC_NONE, NULL),
1526 					NewBlock(OffsetInOut, MaskOutput, ($3 << ShiftOutput) & MaskOutput, CMP_EQ, FUNC_NONE, NULL)
1527 				);
1528 				break;
1529 			case DIR_IN:
1530 				$$.self = NewBlock(OffsetInOut, MaskInput, ($3 << ShiftInput) & MaskInput, CMP_EQ, FUNC_NONE, NULL);
1531 				break;
1532 			case DIR_OUT:
1533 				$$.self = NewBlock(OffsetInOut, MaskOutput, ($3 << ShiftOutput) & MaskOutput, CMP_EQ, FUNC_NONE, NULL);
1534 				break;
1535 			default:
1536 				yyerror("This token is not expected here!");
1537 				YYABORT;
1538 		} // End of switch
1539 
1540 	}
1541 
1542 	| dqual VLAN NUMBER {
1543 		if ( $3 > 65535 ) {
1544 			yyerror("VLAN number of range 0..65535");
1545 			YYABORT;
1546 		}
1547 
1548 		switch ( $1.direction ) {
1549 			case SOURCE:
1550 				$$.self = NewBlock(OffsetVlan, MaskSrcVlan, ($3 << ShiftSrcVlan) & MaskSrcVlan, CMP_EQ, FUNC_NONE, NULL );
1551 				break;
1552 			case DESTINATION:
1553 				$$.self = NewBlock(OffsetVlan, MaskDstVlan, ($3 << ShiftDstVlan) & MaskDstVlan, CMP_EQ, FUNC_NONE, NULL);
1554 				break;
1555 			case DIR_UNSPEC:
1556 			case SOURCE_OR_DESTINATION:
1557 				$$.self = Connect_OR(
1558 					NewBlock(OffsetVlan, MaskSrcVlan, ($3 << ShiftSrcVlan) & MaskSrcVlan, CMP_EQ, FUNC_NONE, NULL ),
1559 					NewBlock(OffsetVlan, MaskDstVlan, ($3 << ShiftDstVlan) & MaskDstVlan, CMP_EQ, FUNC_NONE, NULL)
1560 				);
1561 				break;
1562 			case SOURCE_AND_DESTINATION:
1563 				$$.self = Connect_AND(
1564 					NewBlock(OffsetVlan, MaskSrcVlan, ($3 << ShiftSrcVlan) & MaskSrcVlan, CMP_EQ, FUNC_NONE, NULL ),
1565 					NewBlock(OffsetVlan, MaskDstVlan, ($3 << ShiftDstVlan) & MaskDstVlan, CMP_EQ, FUNC_NONE, NULL)
1566 				);
1567 				break;
1568 			default:
1569 				yyerror("This token is not expected here!");
1570 				YYABORT;
1571 		} // End of switch
1572 
1573 	}
1574 
1575 	| dqual MAC STRING {
1576 		uint64_t	mac = VerifyMac($3);
1577 		if ( mac == 0 ) {
1578 			yyerror("Invalid MAC address format");
1579 			YYABORT;
1580 		}
1581 		switch ( $1.direction ) {
1582 			case DIR_UNSPEC: {
1583 					uint32_t in, out;
1584 					in  = Connect_OR(
1585 						NewBlock(OffsetInSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL ),
1586 						NewBlock(OffsetInDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL )
1587 					);
1588 					out  = Connect_OR(
1589 						NewBlock(OffsetOutSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL ),
1590 						NewBlock(OffsetOutDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL )
1591 					);
1592 					$$.self = Connect_OR(in, out);
1593 					} break;
1594 			case DIR_IN:
1595 					$$.self = Connect_OR(
1596 						NewBlock(OffsetInSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL ),
1597 						NewBlock(OffsetInDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL )
1598 					);
1599 					break;
1600 			case DIR_OUT:
1601 					$$.self = Connect_OR(
1602 						NewBlock(OffsetOutSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL ),
1603 						NewBlock(OffsetOutDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL )
1604 					);
1605 					break;
1606 			case SOURCE:
1607 					$$.self = Connect_OR(
1608 						NewBlock(OffsetInSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL ),
1609 						NewBlock(OffsetOutSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL )
1610 					);
1611 					break;
1612 			case DESTINATION:
1613 					$$.self = Connect_OR(
1614 						NewBlock(OffsetInDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL ),
1615 						NewBlock(OffsetOutDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL )
1616 					);
1617 					break;
1618 			case IN_SRC:
1619 					$$.self = NewBlock(OffsetInSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL );
1620 					break;
1621 			case IN_DST:
1622 					$$.self = NewBlock(OffsetInDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL );
1623 					break;
1624 			case OUT_SRC:
1625 					$$.self = NewBlock(OffsetOutSrcMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL );
1626 					break;
1627 			case OUT_DST:
1628 					$$.self = NewBlock(OffsetOutDstMAC, MaskMac, mac, CMP_EQ, FUNC_NONE, NULL );
1629 					break;
1630 				break;
1631 			default:
1632 				yyerror("This token is not expected here!");
1633 				YYABORT;
1634 		} // End of switch
1635 	}
1636 
1637 	| MPLS STRING comp NUMBER {
1638 		if ( $4 > MPLSMAX ) {
1639 			yyerror("MPLS value out of range");
1640 			YYABORT;
1641 		}
1642 
1643 		// search for label1 - label10
1644 		if ( strncasecmp($2, "label", 5) == 0 ) {
1645 			uint64_t mask;
1646 			uint32_t offset, shift;
1647 			char *s = &$2[5];
1648 			if ( *s == '\0' ) {
1649 				yyerror("Missing label number");
1650 				YYABORT;
1651 			}
1652 			int i = (int)strtol(s, (char **)NULL, 10);
1653 
1654 			switch (i) {
1655 				case 1:
1656 					offset	= OffsetMPLS12;
1657 					mask	= MaskMPLSlabelOdd;
1658 					shift	= ShiftMPLSlabelOdd;
1659 					break;
1660 				case 2:
1661 					offset	= OffsetMPLS12;
1662 					mask	= MaskMPLSlabelEven;
1663 					shift	= ShiftMPLSlabelEven;
1664 					break;
1665 				case 3:
1666 					offset	= OffsetMPLS34;
1667 					mask	= MaskMPLSlabelOdd;
1668 					shift	= ShiftMPLSlabelOdd;
1669 					break;
1670 				case 4:
1671 					offset	= OffsetMPLS34;
1672 					mask	= MaskMPLSlabelEven;
1673 					shift	= ShiftMPLSlabelEven;
1674 					break;
1675 				case 5:
1676 					offset	= OffsetMPLS56;
1677 					mask	= MaskMPLSlabelOdd;
1678 					shift	= ShiftMPLSlabelOdd;
1679 					break;
1680 				case 6:
1681 					offset	= OffsetMPLS56;
1682 					mask	= MaskMPLSlabelEven;
1683 					shift	= ShiftMPLSlabelEven;
1684 					break;
1685 				case 7:
1686 					offset	= OffsetMPLS78;
1687 					mask	= MaskMPLSlabelOdd;
1688 					shift	= ShiftMPLSlabelOdd;
1689 					break;
1690 				case 8:
1691 					offset	= OffsetMPLS78;
1692 					mask	= MaskMPLSlabelEven;
1693 					shift	= ShiftMPLSlabelEven;
1694 					break;
1695 				case 9:
1696 					offset	= OffsetMPLS910;
1697 					mask	= MaskMPLSlabelOdd;
1698 					shift	= ShiftMPLSlabelOdd;
1699 					break;
1700 				case 10:
1701 					offset	= OffsetMPLS910;
1702 					mask	= MaskMPLSlabelEven;
1703 					shift	= ShiftMPLSlabelEven;
1704 					break;
1705 				default:
1706 					yyerror("MPLS label out of range 1..10");
1707 					YYABORT;
1708 			}
1709 			$$.self = NewBlock(offset, mask, ($4 << shift) & mask, $3.comp, FUNC_NONE, NULL );
1710 
1711 		} else if ( strcasecmp($2, "eos") == 0 ) {
1712 			// match End of Stack label
1713 			$$.self = NewBlock(0, AnyMask, $4 << 4, $3.comp, FUNC_MPLS_EOS, NULL );
1714 
1715 		} else if ( strncasecmp($2, "exp", 3) == 0 ) {
1716 			uint64_t mask;
1717 			uint32_t offset, shift;
1718 			char *s = &$2[3];
1719 			if ( *s == '\0' ) {
1720 				yyerror("Missing label number");
1721 				YYABORT;
1722 			}
1723 			int i = (int)strtol(s, (char **)NULL, 10);
1724 
1725 			if ( $4 > 7 ) {
1726 				yyerror("MPLS exp value out of range");
1727 				YYABORT;
1728 			}
1729 
1730 			switch (i) {
1731 				case 1:
1732 					offset	= OffsetMPLS12;
1733 					mask	= MaskMPLSexpOdd;
1734 					shift	= ShiftMPLSexpOdd;
1735 					break;
1736 				case 2:
1737 					offset	= OffsetMPLS12;
1738 					mask	= MaskMPLSexpEven;
1739 					shift	= ShiftMPLSexpEven;
1740 					break;
1741 				case 3:
1742 					offset	= OffsetMPLS34;
1743 					mask	= MaskMPLSexpOdd;
1744 					shift	= ShiftMPLSexpOdd;
1745 					break;
1746 				case 4:
1747 					offset	= OffsetMPLS34;
1748 					mask	= MaskMPLSexpEven;
1749 					shift	= ShiftMPLSexpEven;
1750 					break;
1751 				case 5:
1752 					offset	= OffsetMPLS56;
1753 					mask	= MaskMPLSexpOdd;
1754 					shift	= ShiftMPLSexpOdd;
1755 					break;
1756 				case 6:
1757 					offset	= OffsetMPLS56;
1758 					mask	= MaskMPLSexpEven;
1759 					shift	= ShiftMPLSexpEven;
1760 					break;
1761 				case 7:
1762 					offset	= OffsetMPLS78;
1763 					mask	= MaskMPLSexpOdd;
1764 					shift	= ShiftMPLSexpOdd;
1765 					break;
1766 				case 8:
1767 					offset	= OffsetMPLS78;
1768 					mask	= MaskMPLSexpEven;
1769 					shift	= ShiftMPLSexpEven;
1770 					break;
1771 				case 9:
1772 					offset	= OffsetMPLS910;
1773 					mask	= MaskMPLSexpOdd;
1774 					shift	= ShiftMPLSexpOdd;
1775 					break;
1776 				case 10:
1777 					offset	= OffsetMPLS910;
1778 					mask	= MaskMPLSexpEven;
1779 					shift	= ShiftMPLSexpEven;
1780 					break;
1781 				default:
1782 					yyerror("MPLS label out of range 1..10");
1783 					YYABORT;
1784 			}
1785 			$$.self = NewBlock(offset, mask, $4 << shift, $3.comp, FUNC_NONE, NULL );
1786 
1787 		} else {
1788 			yyerror("Unknown MPLS option");
1789 			YYABORT;
1790 		}
1791 	}
1792 	| MPLS ANY NUMBER {
1793 		uint32_t *opt = malloc(sizeof(uint32_t));
1794 		if ( $3 > MPLSMAX ) {
1795 			yyerror("MPLS value out of range");
1796 			YYABORT;
1797 		}
1798 		if ( opt == NULL) {
1799 			yyerror("malloc() error");
1800 			YYABORT;
1801 		}
1802 		*opt = $3 << 4;
1803 		$$.self = NewBlock(0, AnyMask, $3 << 4, CMP_EQ, FUNC_MPLS_ANY, opt );
1804 
1805 	}
1806 	| FWDSTAT NUMBER {
1807 		if ( $2 > 255 ) {
1808 			yyerror("Forwarding status of range 0..255");
1809 			YYABORT;
1810 		}
1811 		$$.self = NewBlock(OffsetStatus, MaskStatus, ($2 << ShiftStatus) & MaskStatus, CMP_EQ, FUNC_NONE, NULL);
1812 	}
1813 
1814 	| FWDSTAT STRING {
1815 		uint64_t id = Get_fwd_status_id($2);
1816 		if (id == 256 ) {
1817 			yyerror("Unknown forwarding status");
1818 			YYABORT;
1819 		}
1820 
1821 		$$.self = NewBlock(OffsetStatus, MaskStatus, (id << ShiftStatus) & MaskStatus, CMP_EQ, FUNC_NONE, NULL);
1822 
1823 	}
1824 
1825 	| DIR NUMBER {
1826 		if ( $2 > 2 ) {
1827 			yyerror("Flow direction status of range 0, 1");
1828 			YYABORT;
1829 		}
1830 		$$.self = NewBlock(OffsetDir, MaskDir, ($2 << ShiftDir) & MaskDir, CMP_EQ, FUNC_NONE, NULL);
1831 
1832 	}
1833 
1834 	| DIR inout {
1835 		uint64_t dir = 0xFF;
1836 		if ( $2.inout == INGRESS )
1837 			dir = 0;
1838 		else if ( $2.inout == EGRESS )
1839 			dir = 1;
1840 		else {
1841 			yyerror("Flow direction status of range ingress, egress");
1842 			YYABORT;
1843 		}
1844 
1845 		$$.self = NewBlock(OffsetDir, MaskDir, (dir << ShiftDir) & MaskDir, CMP_EQ, FUNC_NONE, NULL);
1846 
1847 	}
1848 
1849 /* iplist definition */
1850 iplist:	STRING	{
1851 		int i, af, bytes, ret;
1852 		struct IPListNode *node;
1853 
1854 		IPlist_t *root = malloc(sizeof(IPlist_t));
1855 
1856 		if ( root == NULL) {
1857 			yyerror("malloc() error");
1858 			YYABORT;
1859 		}
1860 		RB_INIT(root);
1861 
1862 		ret = parse_ip(&af, $1, IPstack, &bytes, ALLOW_LOOKUP, &num_ip);
1863 
1864 		if ( ret == 0 ) {
1865 			yyerror("Invalid IP address");
1866 			YYABORT;
1867 		}
1868 		// ret == -1 will never happen here, as ALLOW_LOOKUP is set
1869 
1870 		if ( ret != -2 ) {
1871 			if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
1872 				yyerror("incomplete IP address");
1873 				YYABORT;
1874 			}
1875 
1876 			for ( i=0; i<num_ip; i++ ) {
1877 				if ((node = malloc(sizeof(struct IPListNode))) == NULL) {
1878 					yyerror("malloc() error");
1879 					YYABORT;
1880 				}
1881 				node->ip[0] = IPstack[2*i];
1882 				node->ip[1] = IPstack[2*i+1];
1883 				node->mask[0] = 0xffffffffffffffffLL;
1884 				node->mask[1] = 0xffffffffffffffffLL;
1885 				RB_INSERT(IPtree, root, node);
1886 			}
1887 
1888 		}
1889 		$$ = (void *)root;
1890 
1891 	}
1892 
1893 iplist:	STRING '/' NUMBER	{
1894 		int af, bytes, ret;
1895 		struct IPListNode *node;
1896 
1897 		IPlist_t *root = malloc(sizeof(IPlist_t));
1898 
1899 		if ( root == NULL) {
1900 			yyerror("malloc() error");
1901 			YYABORT;
1902 		}
1903 		RB_INIT(root);
1904 
1905 		ret = parse_ip(&af, $1, IPstack, &bytes, STRICT_IP, &num_ip);
1906 
1907 		if ( ret == 0 ) {
1908 			yyerror("Invalid IP address");
1909 			YYABORT;
1910 		}
1911 		// ret == -1 will never happen here, as ALLOW_LOOKUP is set
1912 
1913 		if ( ret != -2 ) {
1914 			if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
1915 				yyerror("incomplete IP address");
1916 				YYABORT;
1917 			}
1918 
1919 			if ((node = malloc(sizeof(struct IPListNode))) == NULL) {
1920 				yyerror("malloc() error");
1921 				YYABORT;
1922 			}
1923 
1924 			if ( af == PF_INET ) {
1925 				node->mask[0] = 0xffffffffffffffffLL;
1926 				node->mask[1] = 0xffffffffffffffffLL << ( 32 - $3 );
1927 			} else {	// PF_INET6
1928 				if ( $3 > 64 ) {
1929 					node->mask[0] = 0xffffffffffffffffLL;
1930 					node->mask[1] = 0xffffffffffffffffLL << ( 128 - $3 );
1931 				} else {
1932 					node->mask[0] = 0xffffffffffffffffLL << ( 64 - $3 );
1933 					node->mask[1] = 0;
1934 				}
1935 			}
1936 
1937 			node->ip[0] = IPstack[0] & node->mask[0];
1938 			node->ip[1] = IPstack[1] & node->mask[1];
1939 
1940 			RB_INSERT(IPtree, root, node);
1941 
1942 		}
1943 		$$ = (void *)root;
1944 
1945 	}
1946 
1947 	| iplist STRING {
1948 		int i, af, bytes, ret;
1949 		struct IPListNode *node;
1950 
1951 		ret = parse_ip(&af, $2, IPstack, &bytes, ALLOW_LOOKUP, &num_ip);
1952 
1953 		if ( ret == 0 ) {
1954 			yyerror("Invalid IP address");
1955 			YYABORT;
1956 		}
1957 		if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
1958 			yyerror("incomplete IP address");
1959 			YYABORT;
1960 		}
1961 
1962 		// ret == - 2 means lookup failure
1963 		if ( ret != -2 ) {
1964 			for ( i=0; i<num_ip; i++ ) {
1965 				if ((node = malloc(sizeof(struct IPListNode))) == NULL) {
1966 					yyerror("malloc() error");
1967 					YYABORT;
1968 				}
1969 				node->ip[0] = IPstack[2*i];
1970 				node->ip[1] = IPstack[2*i+1];
1971 				node->mask[0] = 0xffffffffffffffffLL;
1972 				node->mask[1] = 0xffffffffffffffffLL;
1973 
1974 				RB_INSERT(IPtree, (IPlist_t *)$$, node);
1975 			}
1976 		}
1977 	}
1978 	| iplist ',' STRING {
1979 		int i, af, bytes, ret;
1980 		struct IPListNode *node;
1981 
1982 		ret = parse_ip(&af, $3, IPstack, &bytes, ALLOW_LOOKUP, &num_ip);
1983 
1984 		if ( ret == 0 ) {
1985 			yyerror("Invalid IP address");
1986 			YYABORT;
1987 		}
1988 		if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
1989 			yyerror("incomplete IP address");
1990 			YYABORT;
1991 		}
1992 
1993 		// ret == - 2 means lookup failure
1994 		if ( ret != -2 ) {
1995 			for ( i=0; i<num_ip; i++ ) {
1996 				if ((node = malloc(sizeof(struct IPListNode))) == NULL) {
1997 					yyerror("malloc() error");
1998 					YYABORT;
1999 				}
2000 				node->ip[0] = IPstack[2*i];
2001 				node->ip[1] = IPstack[2*i+1];
2002 				node->mask[0] = 0xffffffffffffffffLL;
2003 				node->mask[1] = 0xffffffffffffffffLL;
2004 
2005 				RB_INSERT(IPtree, (IPlist_t *)$$, node);
2006 			}
2007 		}
2008 	}
2009 
2010 	| iplist STRING '/' NUMBER  {
2011 		int af, bytes, ret;
2012 		struct IPListNode *node;
2013 
2014 		ret = parse_ip(&af, $2, IPstack, &bytes, STRICT_IP, &num_ip);
2015 
2016 		if ( ret == 0 ) {
2017 			yyerror("Invalid IP address");
2018 			YYABORT;
2019 		}
2020 		if ( af && (( af == PF_INET && bytes != 4 ) || ( af == PF_INET6 && bytes != 16 ))) {
2021 			yyerror("incomplete IP address");
2022 			YYABORT;
2023 		}
2024 
2025 		// ret == - 2 means lookup failure
2026 		if ( ret != -2 ) {
2027 			if ((node = malloc(sizeof(struct IPListNode))) == NULL) {
2028 				yyerror("malloc() error");
2029 				YYABORT;
2030 			}
2031 			if ( af == PF_INET ) {
2032 				node->mask[0] = 0xffffffffffffffffLL;
2033 				node->mask[1] = 0xffffffffffffffffLL << ( 32 - $4 );
2034 			} else {	// PF_INET6
2035 				if ( $4 > 64 ) {
2036 					node->mask[0] = 0xffffffffffffffffLL;
2037 					node->mask[1] = 0xffffffffffffffffLL << ( 128 - $4 );
2038 				} else {
2039 					node->mask[0] = 0xffffffffffffffffLL << ( 64 - $4 );
2040 					node->mask[1] = 0;
2041 				}
2042 			}
2043 
2044 			node->ip[0] = IPstack[0] & node->mask[0];
2045 			node->ip[1] = IPstack[1] & node->mask[1];
2046 
2047 			RB_INSERT(IPtree, (IPlist_t *)$$, node);
2048 		}
2049 	}
2050 
2051 	;
2052 
2053 /* ULlist definition */
2054 ullist:	NUMBER	{
2055 		struct ULongListNode *node;
2056 
2057 		ULongtree_t *root = malloc(sizeof(ULongtree_t));
2058 
2059 		if ( root == NULL) {
2060 			yyerror("malloc() error");
2061 			YYABORT;
2062 		}
2063 		RB_INIT(root);
2064 
2065 		if ((node = malloc(sizeof(struct ULongListNode))) == NULL) {
2066 			yyerror("malloc() error");
2067 			YYABORT;
2068 		}
2069 		node->value = $1;
2070 
2071 		RB_INSERT(ULongtree, root, node);
2072 		$$ = (void *)root;
2073 	}
2074 
2075 	| ullist NUMBER {
2076 		struct ULongListNode *node;
2077 
2078 		if ((node = malloc(sizeof(struct ULongListNode))) == NULL) {
2079 			yyerror("malloc() error");
2080 			YYABORT;
2081 		}
2082 		node->value = $2;
2083 		RB_INSERT(ULongtree, (ULongtree_t *)$$, node);
2084 	}
2085 
2086 	| ullist ',' NUMBER {
2087 		struct ULongListNode *node;
2088 
2089 		if ((node = malloc(sizeof(struct ULongListNode))) == NULL) {
2090 			yyerror("malloc() error");
2091 			YYABORT;
2092 		}
2093 		node->value = $3;
2094 		RB_INSERT(ULongtree, (ULongtree_t *)$$, node);
2095 	}
2096 
2097 	;
2098 
2099 /* comparator qualifiers */
2100 comp:				{ $$.comp = CMP_EQ; }
2101 	| EQ			{ $$.comp = CMP_EQ; }
2102 	| LT			{ $$.comp = CMP_LT; }
2103 	| GT			{ $$.comp = CMP_GT; }
2104 	;
2105 
2106 /* 'direction' qualifiers */
2107 dqual:	  			{ $$.direction = DIR_UNSPEC;  			 }
2108 	| SRC			{ $$.direction = SOURCE;				 }
2109 	| DST			{ $$.direction = DESTINATION;			 }
2110 	| SRC OR DST 	{ $$.direction = SOURCE_OR_DESTINATION;  }
2111 	| DST OR SRC	{ $$.direction = SOURCE_OR_DESTINATION;  }
2112 	| SRC AND DST	{ $$.direction = SOURCE_AND_DESTINATION; }
2113 	| DST AND SRC	{ $$.direction = SOURCE_AND_DESTINATION; }
2114 	| IN			{ $$.direction = DIR_IN;				 }
2115 	| OUT			{ $$.direction = DIR_OUT;				 }
2116 	| IN SRC		{ $$.direction = IN_SRC;				 }
2117 	| IN DST		{ $$.direction = IN_DST;				 }
2118 	| OUT SRC		{ $$.direction = OUT_SRC;				 }
2119 	| OUT DST		{ $$.direction = OUT_DST;				 }
2120 	| PREV			{ $$.direction = ADJ_PREV;				 }
2121 	| NEXT			{ $$.direction = ADJ_NEXT;				 }
2122 	;
2123 
2124 inout: INGRESS		{ $$.inout	= INGRESS;	}
2125 	|  EGRESS		{ $$.inout	= EGRESS;   }
2126 	;
2127 
2128 acl:	ACL			{ $$.acl = ACL; 	}
2129 	|	ACE			{ $$.acl = ACE;		}
2130 	|	XACE		{ $$.acl = XACE;	}
2131 	;
2132 
2133 expr:	term		{ $$ = $1.self;        }
2134 	| expr OR  expr	{ $$ = Connect_OR($1, $3);  }
2135 	| expr AND expr	{ $$ = Connect_AND($1, $3); }
2136 	| NOT expr	%prec NEGATE	{ $$ = Invert($2);			}
2137 	| '(' expr ')'	{ $$ = $2; }
2138 	| '(' expr ')' '%' STRING	{
2139 		$$ = $2;
2140 		if ( strlen($5) > 16 ) {
2141 			yyerror("Error: Maximum 16 chars allowed for flowlabel");
2142 			YYABORT;
2143 		} else {
2144 			AddLabel($2, $5);
2145 		}
2146 	}
2147 	| '%' STRING '(' expr ')' {
2148 		$$ = $4;
2149 		if ( strlen($2) > 16 ) {
2150 			yyerror("Error: Maximum 16 chars allowed for flowlabel");
2151 			YYABORT;
2152 		} else {
2153 			AddLabel($4, $2);
2154 		}
2155 	}
2156 	;
2157 
2158 %%
2159 
2160 static void  yyerror(char *msg) {
2161 
2162 	if ( FilterFilename )
2163 		snprintf(yyerror_buff, 255 ,"File '%s' line %d: %s at '%s'", FilterFilename, lineno, msg, yytext);
2164 	else
2165 		snprintf(yyerror_buff, 255, "Line %d: %s at '%s'", lineno, msg, yytext);
2166 
2167 	yyerror_buff[255] = '\0';
2168 	fprintf(stderr, "%s\n", yyerror_buff);
2169 
2170 } /* End of yyerror */
2171 
ChainHosts(uint64_t * offsets,uint64_t * hostlist,int num_records,int type)2172 static uint32_t ChainHosts(uint64_t *offsets, uint64_t *hostlist, int num_records, int type) {
2173 uint32_t offset_a, offset_b, i, j, block;
2174 	if ( type == SOURCE ) {
2175 		offset_a = offsets[0];
2176 		offset_b = offsets[1];
2177 	} else {
2178 		offset_a = offsets[2];
2179 		offset_b = offsets[3];
2180 	}
2181 
2182 	i = 0;
2183 	block = Connect_AND(
2184 				NewBlock(offset_b, MaskIPv6, hostlist[i+1] , CMP_EQ, FUNC_NONE, NULL ),
2185 				NewBlock(offset_a, MaskIPv6, hostlist[i] , CMP_EQ, FUNC_NONE, NULL )
2186 			);
2187 	i += 2;
2188 	for ( j=1; j<num_records; j++ ) {
2189 		uint32_t b = Connect_AND(
2190 				NewBlock(offset_b, MaskIPv6, hostlist[i+1] , CMP_EQ, FUNC_NONE, NULL ),
2191 				NewBlock(offset_a, MaskIPv6, hostlist[i] , CMP_EQ, FUNC_NONE, NULL )
2192 			);
2193 		block = Connect_OR(block, b);
2194 		i += 2;
2195 	}
2196 
2197 	return block;
2198 
2199 } // End of ChainHosts
2200 
VerifyMac(char * s)2201 uint64_t VerifyMac(char *s) {
2202 uint64_t mac;
2203 size_t slen = strlen(s);
2204 long l;
2205 char *p, *q, *r;
2206 int i;
2207 
2208 	if ( slen > 17 )
2209 		return 0;
2210 
2211 	for (i=0; i<slen; i++ ) {
2212 		if ( !isxdigit(s[i]) && s[i] != ':' )
2213 			return 0;
2214 	}
2215 
2216 	p = strdup(s);
2217 	if ( !p ) {
2218 		yyerror("malloc() error");
2219 		return 0;
2220 	}
2221 
2222 	mac = 0;
2223 	i = 0;	// number of MAC octets must be 6
2224 	r = p;
2225 	q = strchr(r, ':');
2226 	while ( r && i < 6 ) {
2227 		if ( q )
2228 			*q = '\0';
2229 		l = strtol(r, NULL, 16);
2230 		if ( (i == 0 && errno == EINVAL) ) {
2231 			free(p);
2232 			return 0;
2233 		}
2234 		if ( l > 255 ) {
2235 			free(p);
2236 			return 0;
2237 		}
2238 
2239 		mac = ( mac << 8 ) | (l & 0xFF );
2240 		i++;
2241 
2242 		if ( q ) {
2243 			r = ++q;
2244 			q = strchr(r, ':');
2245 		} else
2246 			r = NULL;
2247 	}
2248 
2249 	if ( i != 6 )
2250 		return 0;
2251 
2252 	return mac;
2253 
2254 } // End of VerifyMac
2255 
InitSymbols(void)2256 static int InitSymbols(void) {
2257 int i;
2258 
2259 	// already initialised?
2260 	if ( fwd_status )
2261 		return 1;
2262 
2263 	// fill fwd status cache table
2264 	fwd_status = ( char **)calloc(256, sizeof(char *));
2265 	if ( !fwd_status ) {
2266 		fprintf(stderr, "malloc(): %s line %d: %s", __FILE__, __LINE__, strerror (errno));
2267 		return 0;
2268 	}
2269 	i=0;
2270 	while ( fwd_status_def_list[i].name ) {
2271 		uint32_t j = fwd_status_def_list[i].id;
2272 		fwd_status[j] = fwd_status_def_list[i].name;
2273 		i++;
2274 	}
2275 	return 1;
2276 
2277 } // End of InitSymbols
2278 
Get_fwd_status_id(char * status)2279 static uint32_t Get_fwd_status_id(char *status) {
2280 int i;
2281 
2282 	if ( !fwd_status && !InitSymbols() )
2283 		yyerror("malloc() error");
2284 
2285 	i = 0;
2286 	while ( i < 256 ) {
2287 		if ( fwd_status[i] && strcasecmp(fwd_status[i], status) == 0 )
2288 			return i;
2289 		i++;
2290 	}
2291 	return 256;
2292 
2293 } // End of Get_fwd_status_id
2294 
2295