xref: /openbsd-src/lib/libpcap/grammar.y (revision 146262ea791a2220a609c41b0b0e51b0a23d9c67)
1 %{
2 /*	$OpenBSD: grammar.y,v 1.24 2024/04/08 02:51:14 jsg Exp $	*/
3 
4 /*
5  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that: (1) source code distributions
10  * retain the above copyright notice and this paragraph in its entirety, (2)
11  * distributions including binary code include the above copyright notice and
12  * this paragraph in its entirety in the documentation or other materials
13  * provided with the distribution, and (3) all advertising materials mentioning
14  * features or use of this software display the following acknowledgement:
15  * ``This product includes software developed by the University of California,
16  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17  * the University nor the names of its contributors may be used to endorse
18  * or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  */
25 
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29 
30 #include <net/if.h>
31 
32 #include <netinet/in.h>
33 #include <netinet/if_ether.h>
34 
35 #include <net/pfvar.h>
36 
37 #include <net80211/ieee80211.h>
38 
39 #include <stdio.h>
40 #include <string.h>
41 
42 #include "pcap-int.h"
43 
44 #include "gencode.h"
45 #include <pcap-namedb.h>
46 
47 #ifdef HAVE_OS_PROTO_H
48 #include "os-proto.h"
49 #endif
50 
51 #define QSET(q, p, d, a) (q).proto = (p),\
52 			 (q).dir = (d),\
53 			 (q).addr = (a)
54 
55 int n_errors = 0;
56 
57 static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
58 
59 static void
yyerror(char * msg)60 yyerror(char *msg)
61 {
62 	++n_errors;
63 	bpf_error("%s", msg);
64 	/* NOTREACHED */
65 }
66 
67 #ifndef YYBISON
68 int yyparse(void);
69 
70 int
pcap_parse(void)71 pcap_parse(void)
72 {
73 	return (yyparse());
74 }
75 #endif
76 
77 %}
78 
79 %union {
80 	int i;
81 	bpf_u_int32 h;
82 	u_char *e;
83 	char *s;
84 	struct stmt *stmt;
85 	struct arth *a;
86 	struct {
87 		struct qual q;
88 		struct block *b;
89 	} blk;
90 	struct block *rblk;
91 }
92 
93 %type	<blk>	expr id nid pid term rterm qid
94 %type	<blk>	head
95 %type	<i>	pqual dqual aqual ndaqual
96 %type	<a>	arth narth
97 %type	<i>	byteop pname pnum relop irelop
98 %type	<blk>	and or paren not null prog
99 %type	<rblk>	other pfvar p80211
100 
101 %token  DST SRC HOST GATEWAY
102 %token  NET MASK PORT LESS GREATER PROTO PROTOCHAIN BYTE
103 %token  ARP RARP IP TCP UDP ICMP IGMP IGRP PIM
104 %token  ATALK DECNET LAT SCA MOPRC MOPDL STP
105 %token  TK_BROADCAST TK_MULTICAST
106 %token  NUM INBOUND OUTBOUND
107 %token  PF_IFNAME PF_RSET PF_RNR PF_SRNR PF_REASON PF_ACTION
108 %token	TYPE SUBTYPE DIR ADDR1 ADDR2 ADDR3 ADDR4
109 %token  LINK
110 %token	GEQ LEQ NEQ
111 %token	ID EID HID HID6
112 %token	LSH RSH
113 %token  LEN RND SAMPLE
114 %token  IPV6 ICMPV6 AH ESP
115 %token	VLAN MPLS
116 
117 %type	<s> ID
118 %type	<e> EID
119 %type	<s> HID HID6
120 %type	<i> NUM action reason type subtype dir
121 
122 %left OR AND
123 %nonassoc  '!'
124 %left '|'
125 %left '&'
126 %left LSH RSH
127 %left '+' '-'
128 %left '*' '/'
129 %nonassoc UMINUS
130 %%
131 prog:	  null expr
132 {
133 	finish_parse($2.b);
134 }
135 	| null
136 	;
137 null:	  /* null */		{ $$.q = qerr; }
138 	;
139 expr:	  term
140 	| expr and term		{ gen_and($1.b, $3.b); $$ = $3; }
141 	| expr and id		{ gen_and($1.b, $3.b); $$ = $3; }
142 	| expr or term		{ gen_or($1.b, $3.b); $$ = $3; }
143 	| expr or id		{ gen_or($1.b, $3.b); $$ = $3; }
144 	;
145 and:	  AND			{ $$ = $<blk>0; }
146 	;
147 or:	  OR			{ $$ = $<blk>0; }
148 	;
149 id:	  nid
150 	| pnum			{ $$.b = gen_ncode(NULL, (bpf_u_int32)$1,
151 						   $$.q = $<blk>0.q); }
152 	| paren pid ')'		{ $$ = $2; }
153 	;
154 nid:	  ID			{ $$.b = gen_scode($1, $$.q = $<blk>0.q); }
155 	| HID '/' NUM		{ $$.b = gen_mcode($1, NULL, $3,
156 				    $$.q = $<blk>0.q); }
157 	| HID MASK HID		{ $$.b = gen_mcode($1, $3, 0,
158 				    $$.q = $<blk>0.q); }
159 	| HID			{
160 				  /* Decide how to parse HID based on proto */
161 				  $$.q = $<blk>0.q;
162 				  switch ($$.q.proto) {
163 				  case Q_DECNET:
164 					$$.b = gen_ncode($1, 0, $$.q);
165 					break;
166 				  default:
167 					$$.b = gen_ncode($1, 0, $$.q);
168 					break;
169 				  }
170 				}
171 	| HID6 '/' NUM		{
172 #ifdef INET6
173 				  $$.b = gen_mcode6($1, NULL, $3,
174 				    $$.q = $<blk>0.q);
175 #else
176 				  bpf_error("'ip6addr/prefixlen' not supported "
177 					"in this configuration");
178 #endif /*INET6*/
179 				}
180 	| HID6			{
181 #ifdef INET6
182 				  $$.b = gen_mcode6($1, 0, 128,
183 				    $$.q = $<blk>0.q);
184 #else
185 				  bpf_error("'ip6addr' not supported "
186 					"in this configuration");
187 #endif /*INET6*/
188 				}
189 	| EID			{ $$.b = gen_ecode($1, $$.q = $<blk>0.q); }
190 	| not id		{ gen_not($2.b); $$ = $2; }
191 	;
192 not:	  '!'			{ $$ = $<blk>0; }
193 	;
194 paren:	  '('			{ $$ = $<blk>0; }
195 	;
196 pid:	  nid
197 	| qid and id		{ gen_and($1.b, $3.b); $$ = $3; }
198 	| qid or id		{ gen_or($1.b, $3.b); $$ = $3; }
199 	;
200 qid:	  pnum			{ $$.b = gen_ncode(NULL, (bpf_u_int32)$1,
201 						   $$.q = $<blk>0.q); }
202 	| pid
203 	;
204 term:	  rterm
205 	| not term		{ gen_not($2.b); $$ = $2; }
206 	;
207 head:	  pqual dqual aqual	{ QSET($$.q, $1, $2, $3); }
208 	| pqual dqual		{ QSET($$.q, $1, $2, Q_DEFAULT); }
209 	| pqual aqual		{ QSET($$.q, $1, Q_DEFAULT, $2); }
210 	| pqual PROTO		{ QSET($$.q, $1, Q_DEFAULT, Q_PROTO); }
211 	| pqual PROTOCHAIN	{ QSET($$.q, $1, Q_DEFAULT, Q_PROTOCHAIN); }
212 	| pqual ndaqual		{ QSET($$.q, $1, Q_DEFAULT, $2); }
213 	;
214 rterm:	  head id		{ $$ = $2; }
215 	| paren expr ')'	{ $$.b = $2.b; $$.q = $1.q; }
216 	| pname			{ $$.b = gen_proto_abbrev($1); $$.q = qerr; }
217 	| arth relop arth	{ $$.b = gen_relation($2, $1, $3, 0);
218 				  $$.q = qerr; }
219 	| arth irelop arth	{ $$.b = gen_relation($2, $1, $3, 1);
220 				  $$.q = qerr; }
221 	| other			{ $$.b = $1; $$.q = qerr; }
222 	;
223 /* protocol level qualifiers */
224 pqual:	  pname
225 	|			{ $$ = Q_DEFAULT; }
226 	;
227 /* 'direction' qualifiers */
228 dqual:	  SRC			{ $$ = Q_SRC; }
229 	| DST			{ $$ = Q_DST; }
230 	| SRC OR DST		{ $$ = Q_OR; }
231 	| DST OR SRC		{ $$ = Q_OR; }
232 	| SRC AND DST		{ $$ = Q_AND; }
233 	| DST AND SRC		{ $$ = Q_AND; }
234 	| ADDR1			{ $$ = Q_ADDR1; }
235 	| ADDR2			{ $$ = Q_ADDR2; }
236 	| ADDR3			{ $$ = Q_ADDR3; }
237 	| ADDR4			{ $$ = Q_ADDR4; }
238 	;
239 
240 /* address type qualifiers */
241 aqual:	  HOST			{ $$ = Q_HOST; }
242 	| NET			{ $$ = Q_NET; }
243 	| PORT			{ $$ = Q_PORT; }
244 	;
245 /* non-directional address type qualifiers */
246 ndaqual:  GATEWAY		{ $$ = Q_GATEWAY; }
247 	;
248 pname:	  LINK			{ $$ = Q_LINK; }
249 	| IP			{ $$ = Q_IP; }
250 	| ARP			{ $$ = Q_ARP; }
251 	| RARP			{ $$ = Q_RARP; }
252 	| TCP			{ $$ = Q_TCP; }
253 	| UDP			{ $$ = Q_UDP; }
254 	| ICMP			{ $$ = Q_ICMP; }
255 	| IGMP			{ $$ = Q_IGMP; }
256 	| IGRP			{ $$ = Q_IGRP; }
257 	| PIM			{ $$ = Q_PIM; }
258 	| ATALK			{ $$ = Q_ATALK; }
259 	| DECNET		{ $$ = Q_DECNET; }
260 	| LAT			{ $$ = Q_LAT; }
261 	| SCA			{ $$ = Q_SCA; }
262 	| MOPDL			{ $$ = Q_MOPDL; }
263 	| MOPRC			{ $$ = Q_MOPRC; }
264 	| IPV6			{ $$ = Q_IPV6; }
265 	| ICMPV6		{ $$ = Q_ICMPV6; }
266 	| AH			{ $$ = Q_AH; }
267 	| ESP			{ $$ = Q_ESP; }
268 	| STP			{ $$ = Q_STP; }
269 	;
270 other:	  pqual TK_BROADCAST	{ $$ = gen_broadcast($1); }
271 	| pqual TK_MULTICAST	{ $$ = gen_multicast($1); }
272 	| LESS NUM		{ $$ = gen_less($2); }
273 	| GREATER NUM		{ $$ = gen_greater($2); }
274 	| BYTE NUM byteop NUM	{ $$ = gen_byteop($3, $2, $4); }
275 	| INBOUND		{ $$ = gen_inbound(0); }
276 	| OUTBOUND		{ $$ = gen_inbound(1); }
277 	| VLAN pnum		{ $$ = gen_vlan($2); }
278 	| VLAN			{ $$ = gen_vlan(-1); }
279 	| MPLS pnum		{ $$ = gen_mpls($2); }
280 	| MPLS			{ $$ = gen_mpls(-1); }
281 	| pfvar			{ $$ = $1; }
282 	| pqual p80211		{ $$ = $2; }
283 	| SAMPLE NUM		{ $$ = gen_sample($2); }
284 	;
285 
286 pfvar:	  PF_IFNAME ID		{ $$ = gen_pf_ifname($2); }
287 	| PF_RSET ID		{ $$ = gen_pf_ruleset($2); }
288 	| PF_RNR NUM		{ $$ = gen_pf_rnr($2); }
289 	| PF_SRNR NUM		{ $$ = gen_pf_srnr($2); }
290 	| PF_REASON reason	{ $$ = gen_pf_reason($2); }
291 	| PF_ACTION action	{ $$ = gen_pf_action($2); }
292 	;
293 
294 reason:	  NUM			{ $$ = $1; }
295 	| ID			{ const char *reasons[] = PFRES_NAMES;
296 				  int i;
297 				  for (i = 0; reasons[i]; i++) {
298 					  if (strcasecmp($1, reasons[i]) == 0) {
299 						  $$ = i;
300 						  break;
301 					  }
302 				  }
303 				  if (reasons[i] == NULL)
304 					  bpf_error("unknown PF reason");
305 				}
306 	;
307 
308 action:	  ID			{ if (strcasecmp($1, "pass") == 0 ||
309 				      strcasecmp($1, "accept") == 0)
310 					$$ = PF_PASS;
311 				  else if (strcasecmp($1, "drop") == 0 ||
312 				      strcasecmp($1, "block") == 0)
313 					$$ = PF_DROP;
314 				  else if (strcasecmp($1, "match") == 0)
315 					$$ = PF_MATCH;
316 				  else if (strcasecmp($1, "rdr") == 0)
317 				  	$$ = PF_RDR;
318 				  else if (strcasecmp($1, "nat") == 0)
319 				  	$$ = PF_NAT;
320 				  else if (strcasecmp($1, "binat") == 0)
321 				  	$$ = PF_BINAT;
322 				  else if (strcasecmp($1, "scrub") == 0)
323 				  	$$ = PF_SCRUB;
324 				  else
325 					  bpf_error("unknown PF action");
326 				}
327 	;
328 
329 p80211:   TYPE type SUBTYPE subtype
330 				{ $$ = gen_p80211_type($2 | $4,
331 					IEEE80211_FC0_TYPE_MASK |
332 					IEEE80211_FC0_SUBTYPE_MASK);
333 				}
334 	| TYPE type		{ $$ = gen_p80211_type($2,
335 					IEEE80211_FC0_TYPE_MASK); }
336 	| SUBTYPE subtype	{ $$ = gen_p80211_type($2,
337 					IEEE80211_FC0_SUBTYPE_MASK); }
338 	| DIR dir		{ $$ = gen_p80211_fcdir($2); }
339 	;
340 
341 type:	  NUM
342 	| ID			{ if (strcasecmp($1, "data") == 0)
343 					$$ = IEEE80211_FC0_TYPE_DATA;
344 				  else if (strcasecmp($1, "mgt") == 0 ||
345 					strcasecmp($1, "management") == 0)
346 					$$ = IEEE80211_FC0_TYPE_MGT;
347 				  else if (strcasecmp($1, "ctl") == 0 ||
348 					strcasecmp($1, "control") == 0)
349 					$$ = IEEE80211_FC0_TYPE_CTL;
350 				  else
351 					  bpf_error("unknown 802.11 type");
352 				}
353 	;
354 
355 subtype:  NUM
356 	| ID			{ if (strcasecmp($1, "assocreq") == 0)
357 					$$ = IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
358 				  else if (strcasecmp($1, "assocresp") == 0)
359 					$$ = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
360 				  else if (strcasecmp($1, "reassocreq") == 0)
361 					$$ = IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
362 				  else if (strcasecmp($1, "reassocresp") == 0)
363 					$$ = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
364 				  else if (strcasecmp($1, "probereq") == 0)
365 					$$ = IEEE80211_FC0_SUBTYPE_PROBE_REQ;
366 				  else if (strcasecmp($1, "proberesp") == 0)
367 					$$ = IEEE80211_FC0_SUBTYPE_PROBE_RESP;
368 				  else if (strcasecmp($1, "beacon") == 0)
369 					$$ = IEEE80211_FC0_SUBTYPE_BEACON;
370 				  else if (strcasecmp($1, "atim") == 0)
371 					$$ = IEEE80211_FC0_SUBTYPE_ATIM;
372 				  else if (strcasecmp($1, "disassoc") == 0 ||
373 				      strcasecmp($1, "disassociation") == 0)
374 					$$ = IEEE80211_FC0_SUBTYPE_DISASSOC;
375 				  else if (strcasecmp($1, "auth") == 0 ||
376 				      strcasecmp($1, "authentication") == 0)
377 					$$ = IEEE80211_FC0_SUBTYPE_AUTH;
378 				  else if (strcasecmp($1, "deauth") == 0 ||
379 				      strcasecmp($1, "deauthentication") == 0)
380 					$$ = IEEE80211_FC0_SUBTYPE_DEAUTH;
381 				  else if (strcasecmp($1, "data") == 0)
382 					$$ = IEEE80211_FC0_SUBTYPE_DATA;
383 				  else
384 					  bpf_error("unknown 802.11 subtype");
385 				}
386 	;
387 
388 dir:	  NUM
389 	| ID			{ if (strcasecmp($1, "nods") == 0)
390 					$$ = IEEE80211_FC1_DIR_NODS;
391 				  else if (strcasecmp($1, "tods") == 0)
392 					$$ = IEEE80211_FC1_DIR_TODS;
393 				  else if (strcasecmp($1, "fromds") == 0)
394 					$$ = IEEE80211_FC1_DIR_FROMDS;
395 				  else if (strcasecmp($1, "dstods") == 0)
396 					$$ = IEEE80211_FC1_DIR_DSTODS;
397 				  else
398 					bpf_error("unknown 802.11 direction");
399 				}
400 	;
401 
402 relop:	  '>'			{ $$ = BPF_JGT; }
403 	| GEQ			{ $$ = BPF_JGE; }
404 	| '='			{ $$ = BPF_JEQ; }
405 	;
406 irelop:	  LEQ			{ $$ = BPF_JGT; }
407 	| '<'			{ $$ = BPF_JGE; }
408 	| NEQ			{ $$ = BPF_JEQ; }
409 	;
410 arth:	  pnum			{ $$ = gen_loadi($1); }
411 	| narth
412 	;
413 narth:	  pname '[' arth ']'		{ $$ = gen_load($1, $3, 1); }
414 	| pname '[' arth ':' NUM ']'	{ $$ = gen_load($1, $3, $5); }
415 	| arth '+' arth			{ $$ = gen_arth(BPF_ADD, $1, $3); }
416 	| arth '-' arth			{ $$ = gen_arth(BPF_SUB, $1, $3); }
417 	| arth '*' arth			{ $$ = gen_arth(BPF_MUL, $1, $3); }
418 	| arth '/' arth			{ $$ = gen_arth(BPF_DIV, $1, $3); }
419 	| arth '&' arth			{ $$ = gen_arth(BPF_AND, $1, $3); }
420 	| arth '|' arth			{ $$ = gen_arth(BPF_OR, $1, $3); }
421 	| arth LSH arth			{ $$ = gen_arth(BPF_LSH, $1, $3); }
422 	| arth RSH arth			{ $$ = gen_arth(BPF_RSH, $1, $3); }
423 	| '-' arth %prec UMINUS		{ $$ = gen_neg($2); }
424 	| paren narth ')'		{ $$ = $2; }
425 	| LEN				{ $$ = gen_loadlen(); }
426 	| RND				{ $$ = gen_loadrnd(); }
427 	;
428 byteop:	  '&'			{ $$ = '&'; }
429 	| '|'			{ $$ = '|'; }
430 	| '<'			{ $$ = '<'; }
431 	| '>'			{ $$ = '>'; }
432 	| '='			{ $$ = '='; }
433 	;
434 pnum:	  NUM
435 	| paren pnum ')'	{ $$ = $2; }
436 	;
437 %%
438