xref: /illumos-gate/usr/src/cmd/ipf/tools/ipmon_y.y (revision 1a220b56b93ff1dc80855691548503117af4cc10)
1 %{
2 #include "ipf.h"
3 #undef	OPT_NAT
4 #undef	OPT_VERBOSE
5 #include "ipmon_l.h"
6 #include "ipmon.h"
7 
8 #define	YYDEBUG	1
9 
10 extern	void	yyerror __P((char *));
11 extern	int	yyparse __P((void));
12 extern	int	yylex __P((void));
13 extern	int	yydebug;
14 extern	FILE	*yyin;
15 extern	int	yylineNum;
16 
17 typedef	struct	opt	{
18 	struct	opt	*o_next;
19 	int		o_line;
20 	int		o_type;
21 	int		o_num;
22 	char		*o_str;
23 	struct in_addr	o_ip;
24 } opt_t;
25 
26 static	void	build_action __P((struct opt *));
27 static	opt_t	*new_opt __P((int));
28 
29 static	action_t	*alist = NULL;
30 %}
31 
32 %union	{
33 	char	*str;
34 	u_32_t	num;
35 	struct in_addr	addr;
36 	struct opt	*opt;
37 	union	i6addr	ip6;
38 }
39 
40 %token  <num>   YY_NUMBER YY_HEX
41 %token  <str>   YY_STR
42 %token	  YY_COMMENT
43 %token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
44 %token	  YY_RANGE_OUT YY_RANGE_IN
45 %token  <ip6>   YY_IPV6
46 
47 %token	IPM_ACTION IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
48 %token	IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT
49 %token	IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
50 %token	IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_TAG IPM_YES
51 %type	<addr> ipv4
52 %type	<opt> direction dstip dstport every execute group interface option
53 %type	<opt> options protocol result rule srcip srcport tag
54 
55 %%
56 file:	line
57 	| assign
58 	| file line
59 	| file assign
60 	;
61 
62 line:	IPM_ACTION '{' options '}' ';'	{ build_action($3); resetlexer(); }
63 	| IPM_COMMENT
64 	;
65 
66 assign:	YY_STR assigning YY_STR ';'		{ set_variable($1, $3);
67 						  resetlexer();
68 						  free($1);
69 						  free($3);
70 						}
71 	;
72 
73 assigning:
74 	'='					{ yyvarnext = 1; }
75 	;
76 
77 options:
78 	option					{ $$ = $1; }
79 	| option ',' options			{ $1->o_next = $3; $$ = $1; }
80 	;
81 
82 option:	direction				{ $$ = $1; }
83 	| dstip					{ $$ = $1; }
84 	| dstport				{ $$ = $1; }
85 	| every					{ $$ = $1; }
86 	| execute				{ $$ = $1; }
87 	| group					{ $$ = $1; }
88 	| interface				{ $$ = $1; }
89 	| protocol				{ $$ = $1; }
90 	| result				{ $$ = $1; }
91 	| rule					{ $$ = $1; }
92 	| srcip					{ $$ = $1; }
93 	| srcport				{ $$ = $1; }
94 	| tag					{ $$ = $1; }
95 	;
96 
97 direction:
98 	IPM_DIRECTION '=' IPM_IN		{ $$ = new_opt(IPM_DIRECTION);
99 						  $$->o_num = IPM_IN; }
100 	| IPM_DIRECTION '=' IPM_OUT		{ $$ = new_opt(IPM_DIRECTION);
101 						  $$->o_num = IPM_OUT; }
102 	;
103 
104 dstip:	IPM_DSTIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_DSTIP);
105 						  $$->o_ip = $3;
106 						  $$->o_num = $5; }
107 	;
108 
109 dstport:
110 	IPM_DSTPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_DSTPORT);
111 						  $$->o_num = $3; }
112 	| IPM_DSTPORT '=' YY_STR		{ $$ = new_opt(IPM_DSTPORT);
113 						  $$->o_str = $3; }
114 	;
115 
116 every:	IPM_EVERY IPM_SECOND			{ $$ = new_opt(IPM_SECOND);
117 						  $$->o_num = 1; }
118 	| IPM_EVERY YY_NUMBER IPM_SECONDS	{ $$ = new_opt(IPM_SECOND);
119 						  $$->o_num = $2; }
120 	| IPM_EVERY IPM_PACKET			{ $$ = new_opt(IPM_PACKET);
121 						  $$->o_num = 1; }
122 	| IPM_EVERY YY_NUMBER IPM_PACKETS	{ $$ = new_opt(IPM_PACKET);
123 						  $$->o_num = $2; }
124 	;
125 
126 execute:
127 	IPM_EXECUTE '=' YY_STR			{ $$ = new_opt(IPM_EXECUTE);
128 						  $$->o_str = $3; }
129 	;
130 
131 group:	IPM_GROUP '=' YY_NUMBER			{ $$ = new_opt(IPM_GROUP);
132 						  $$->o_num = $3; }
133 	| IPM_GROUP '=' YY_STR			{ $$ = new_opt(IPM_GROUP);
134 						  $$->o_str = $3; }
135 	;
136 
137 interface:
138 	IPM_INTERFACE '=' YY_STR		{ $$ = new_opt(IPM_INTERFACE);
139 						  $$->o_str = $3; }
140 	;
141 
142 protocol:
143 	IPM_PROTOCOL '=' YY_NUMBER		{ $$ = new_opt(IPM_PROTOCOL);
144 						  $$->o_num = $3; }
145 	| IPM_PROTOCOL '=' YY_STR		{ $$ = new_opt(IPM_PROTOCOL);
146 						  $$->o_num = getproto($3);
147 						  free($3);
148 						}
149 	;
150 
151 result:	IPM_RESULT '=' YY_STR			{ $$ = new_opt(IPM_RESULT);
152 						  $$->o_str = $3; }
153 	;
154 
155 rule:	IPM_RULE '=' YY_NUMBER			{ $$ = new_opt(IPM_RULE);
156 						  $$->o_num = YY_NUMBER; }
157 	;
158 
159 srcip:	IPM_SRCIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_SRCIP);
160 						  $$->o_ip = $3;
161 						  $$->o_num = $5; }
162 	;
163 
164 srcport:
165 	IPM_SRCPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_SRCPORT);
166 						  $$->o_num = $3; }
167 	| IPM_SRCPORT '=' YY_STR		{ $$ = new_opt(IPM_SRCPORT);
168 						  $$->o_str = $3; }
169 	;
170 
171 tag:	IPM_TAG '=' YY_NUMBER			{ $$ = new_opt(IPM_TAG);
172 						  $$->o_num = $3; }
173 	;
174 
175 ipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
176 		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
177 			yyerror("Invalid octet string for IP address");
178 			return 0;
179 		  }
180 		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
181 		  $$.s_addr = htonl($$.s_addr);
182 		}
183 %%
184 static	struct	wordtab	yywords[] = {
185 	{ "action",	IPM_ACTION },
186 	{ "body",	IPM_BODY },
187 	{ "direction",	IPM_DIRECTION },
188 	{ "dstip",	IPM_DSTIP },
189 	{ "dstport",	IPM_DSTPORT },
190 	{ "every",	IPM_EVERY },
191 	{ "execute",	IPM_EXECUTE },
192 	{ "group",	IPM_GROUP },
193 	{ "in",		IPM_IN },
194 	{ "interface",	IPM_INTERFACE },
195 	{ "no",		IPM_NO },
196 	{ "out",	IPM_OUT },
197 	{ "packet",	IPM_PACKET },
198 	{ "packets",	IPM_PACKETS },
199 	{ "protocol",	IPM_PROTOCOL },
200 	{ "result",	IPM_RESULT },
201 	{ "rule",	IPM_RULE },
202 	{ "second",	IPM_SECOND },
203 	{ "seconds",	IPM_SECONDS },
204 	{ "srcip",	IPM_SRCIP },
205 	{ "srcport",	IPM_SRCPORT },
206 	{ "tag",	IPM_TAG },
207 	{ "yes",	IPM_YES },
208 	{ NULL,		0 }
209 };
210 
211 static int macflags[15][2] = {
212 	{ IPM_DIRECTION,	IPMAC_DIRECTION	},
213 	{ IPM_DSTIP,		IPMAC_DSTIP	},
214 	{ IPM_DSTPORT,		IPMAC_DSTPORT	},
215 	{ IPM_EXECUTE,		IPMAC_EXECUTE	},
216 	{ IPM_GROUP,		IPMAC_GROUP	},
217 	{ IPM_INTERFACE,	IPMAC_INTERFACE	},
218 	{ IPM_PACKET,		IPMAC_EVERY	},
219 	{ IPM_PROTOCOL,		IPMAC_PROTOCOL	},
220 	{ IPM_RESULT,		IPMAC_RESULT	},
221 	{ IPM_RULE,		IPMAC_RULE	},
222 	{ IPM_SECOND,		IPMAC_EVERY	},
223 	{ IPM_SRCIP,		IPMAC_SRCIP	},
224 	{ IPM_SRCPORT,		IPMAC_SRCPORT	},
225 	{ IPM_TAG,		IPMAC_TAG 	},
226 	{ 0, 0 }
227 };
228 
229 static opt_t *new_opt(type)
230 int type;
231 {
232 	opt_t *o;
233 
234 	o = (opt_t *)malloc(sizeof(*o));
235 	if (o == NULL)
236 		yyerror("sorry, out of memory");
237 	o->o_type = type;
238 	o->o_line = yylineNum;
239 	o->o_num = 0;
240 	o->o_str = (char *)0;
241 	return o;
242 }
243 
244 static void build_action(olist)
245 opt_t *olist;
246 {
247 	action_t *a;
248 	opt_t *o;
249 	u_32_t m;
250 	char c;
251 	int i;
252 
253 	a = (action_t *)calloc(1, sizeof(*a));
254 	if (!a)
255 		return;
256 	while ((o = olist)) {
257 		for (i = 0; macflags[i][0]; i++)
258 			if (macflags[i][0] == o->o_type)
259 				break;
260 		if (macflags[i][1] & a->ac_mflag) {
261 			fprintf(stderr, "%s redfined on line %d\n",
262 				yykeytostr(o->o_type), yylineNum);
263 			if (o->o_str != NULL)
264 				free(o->o_str);
265 			olist = o->o_next;
266 			free(o);
267 			continue;
268 		}
269 
270 		a->ac_mflag |= macflags[i][1];
271 
272 		switch (o->o_type)
273 		{
274 		case IPM_DIRECTION :
275 			a->ac_direction = o->o_num;
276 			break;
277 		case IPM_DSTIP :
278 			a->ac_dip = o->o_ip.s_addr;
279 			for (i = o->o_num, m = 0; i; i--) {
280 				m >>= 1;
281 				m |= 0x80000000;
282 			}
283 			a->ac_dmsk = htonl(m);
284 			break;
285 		case IPM_DSTPORT :
286 			a->ac_dport = htons(o->o_num);
287 			break;
288 		case IPM_EXECUTE :
289 			a->ac_exec = o->o_str;
290 			c = *o->o_str;
291 			if (c== '"'|| c == '\'') {
292 				if (o->o_str[strlen(o->o_str) - 1] == c) {
293 					a->ac_run = strdup(o->o_str + 1);
294 					a->ac_run[strlen(a->ac_run) - 1] ='\0';
295 				} else
296 					a->ac_run = o->o_str;
297 			} else
298 				a->ac_run = o->o_str;
299 			o->o_str = NULL;
300 			break;
301 		case IPM_INTERFACE :
302 			a->ac_iface = o->o_str;
303 			o->o_str = NULL;
304 			break;
305 		case IPM_GROUP :
306 			if (o->o_str != NULL)
307 				strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
308 			else
309 				sprintf(a->ac_group, "%d", o->o_num);
310 			break;
311 		case IPM_PACKET :
312 			a->ac_packet = o->o_num;
313 			break;
314 		case IPM_PROTOCOL :
315 			a->ac_proto = o->o_num;
316 			break;
317 		case IPM_RULE :
318 			a->ac_rule = o->o_num;
319 			break;
320 		case IPM_RESULT :
321 			if (!strcasecmp(o->o_str, "pass"))
322 				a->ac_result = IPMR_PASS;
323 			else if (!strcasecmp(o->o_str, "block"))
324 				a->ac_result = IPMR_BLOCK;
325 			else if (!strcasecmp(o->o_str, "short"))
326 				a->ac_result = IPMR_SHORT;
327 			else if (!strcasecmp(o->o_str, "nomatch"))
328 				a->ac_result = IPMR_NOMATCH;
329 			else if (!strcasecmp(o->o_str, "log"))
330 				a->ac_result = IPMR_LOG;
331 			break;
332 		case IPM_SECOND :
333 			a->ac_second = o->o_num;
334 			break;
335 		case IPM_SRCIP :
336 			a->ac_sip = o->o_ip.s_addr;
337 			for (i = o->o_num, m = 0; i; i--) {
338 				m >>= 1;
339 				m |= 0x80000000;
340 			}
341 			a->ac_smsk = htonl(m);
342 			break;
343 		case IPM_SRCPORT :
344 			a->ac_sport = htons(o->o_num);
345 			break;
346 		case IPM_TAG :
347 			a->ac_tag = o->o_num;
348 			break;
349 		default :
350 			break;
351 		}
352 
353 		olist = o->o_next;
354 		if (o->o_str != NULL)
355 			free(o->o_str);
356 		free(o);
357 	}
358 	a->a_next = alist;
359 	alist = a;
360 }
361 
362 
363 void check_action(buf, opts, log)
364 char *buf;
365 int opts;
366 char *log;
367 {
368 	struct timeval tv;
369 	ipflog_t *ipf;
370 	tcphdr_t *tcp;
371 	iplog_t *ipl;
372 	action_t *a;
373 	u_long t1;
374 	ip_t *ip;
375 
376 	ipl = (iplog_t *)buf;
377 	ipf = (ipflog_t *)(ipl +1);
378 	ip = (ip_t *)(ipf + 1);
379 	tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
380 
381 	for (a = alist; a; a = a->a_next) {
382 		if (a->ac_mflag & IPMAC_DIRECTION) {
383 			if (a->ac_direction == IPM_IN) {
384 				if (!(ipf->fl_flags & FR_INQUE))
385 					continue;
386 			} else if (a->ac_direction == IPM_OUT) {
387 				if (!(ipf->fl_flags & FR_OUTQUE))
388 					continue;
389 			}
390 		}
391 
392 		if (a->ac_mflag & IPMAC_EVERY) {
393 			gettimeofday(&tv, NULL);
394 			t1 = tv.tv_sec - a->ac_lastsec;
395 			if (tv.tv_usec <= a->ac_lastusec)
396 				t1--;
397 			if (a->ac_second) {
398 				if (t1 < a->ac_second)
399 					continue;
400 				a->ac_lastsec = tv.tv_sec;
401 				a->ac_lastusec = tv.tv_usec;
402 			}
403 
404 			if (a->ac_packet) {
405 				if (!a->ac_pktcnt)
406 					a->ac_pktcnt++;
407 				else if (a->ac_pktcnt == a->ac_packet) {
408 					a->ac_pktcnt = 0;
409 					continue;
410 				} else {
411 					a->ac_pktcnt++;
412 					continue;
413 				}
414 			}
415 		}
416 
417 		if (a->ac_mflag & IPMAC_DSTIP) {
418 			if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip)
419 				continue;
420 		}
421 
422 		if (a->ac_mflag & IPMAC_DSTPORT) {
423 			if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
424 				continue;
425 			if (tcp->th_dport != a->ac_dport)
426 				continue;
427 		}
428 
429 		if (a->ac_mflag & IPMAC_GROUP) {
430 			if (strncmp(a->ac_group, ipf->fl_group,
431 				    FR_GROUPLEN) != 0)
432 				continue;
433 		}
434 
435 		if (a->ac_mflag & IPMAC_INTERFACE) {
436 			if (strcmp(a->ac_iface, ipf->fl_ifname))
437 				continue;
438 		}
439 
440 		if (a->ac_mflag & IPMAC_PROTOCOL) {
441 			if (a->ac_proto != ip->ip_p)
442 				continue;
443 		}
444 
445 		if (a->ac_mflag & IPMAC_RESULT) {
446 			if (ipf->fl_lflags & FI_SHORT) {
447 				if (a->ac_result != IPMR_SHORT)
448 					continue;
449 			} else if (FR_ISPASS(ipf->fl_flags)) {
450 				if (a->ac_result != IPMR_PASS)
451 					continue;
452 			} else if (FR_ISBLOCK(ipf->fl_flags)) {
453 				if (a->ac_result != IPMR_BLOCK)
454 					continue;
455 			} else if (ipf->fl_flags & FF_LOGNOMATCH) {
456 				if (a->ac_result != IPMR_NOMATCH)
457 					continue;
458 			} else {	/* Log only */
459 				if (a->ac_result != IPMR_LOG)
460 					continue;
461 			}
462 		}
463 
464 		if (a->ac_mflag & IPMAC_RULE) {
465 			if (a->ac_rule != ipf->fl_rule)
466 				continue;
467 		}
468 
469 		if (a->ac_mflag & IPMAC_SRCIP) {
470 			if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip)
471 				continue;
472 		}
473 
474 		if (a->ac_mflag & IPMAC_SRCPORT) {
475 			if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
476 				continue;
477 			if (tcp->th_sport != a->ac_sport)
478 				continue;
479 		}
480 
481 		if (a->ac_mflag & IPMAC_TAG) {
482 			if (a->ac_tag != ipf->fl_tag)
483 				continue;
484 		}
485 
486 		/*
487 		 * It matched so now execute the command
488 		 */
489 		if (a->ac_exec) {
490 			switch (fork())
491 			{
492 			case 0 :
493 			{
494 				FILE *pi;
495 
496 				pi = popen(a->ac_run, "w");
497 				if (pi) {
498 					fprintf(pi, "%s\n", log);
499 					if (opts & OPT_HEXHDR) {
500 						dumphex(pi, 0, buf,
501 							sizeof(*ipl) +
502 							sizeof(*ipf));
503 					}
504 					if (opts & OPT_HEXBODY) {
505 						dumphex(pi, 0, (char *)ip,
506 							ipf->fl_hlen +
507 							ipf->fl_plen);
508 					}
509 					pclose(pi);
510 				}
511 				exit(1);
512 			}
513 			case -1 :
514 				break;
515 			default :
516 				break;
517 			}
518 		}
519 	}
520 }
521 
522 
523 int load_config(file)
524 char *file;
525 {
526 	FILE *fp;
527 
528 	yylineNum = 0;
529 
530 	(void) yysettab(yywords);
531 
532 	fp = fopen(file, "r");
533 	if (!fp) {
534 		perror("load_config:fopen:");
535 		return -1;
536 	}
537 	yyin = fp;
538 	while (!feof(fp))
539 		yyparse();
540 	fclose(fp);
541 	return 0;
542 }
543