4 * Copyright (C) 2001-2004 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
18 extern
void yyerror __P
((char *));
19 extern
int yyparse __P
((void));
20 extern
int yylex __P
((void));
34 static void build_action __P
((struct opt
*));
35 static opt_t
*new_opt __P
((int));
36 static void free_action __P
((ipmon_action_t
*));
38 static ipmon_action_t
*alist
= NULL
;
49 %token
<num
> YY_NUMBER YY_HEX
53 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
54 %token YY_RANGE_OUT YY_RANGE_IN
56 %token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
57 %token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT
58 %token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
59 %token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
60 %token IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT
61 %token IPM_STATE IPM_NATTAG IPM_IPF
63 %type
<opt
> direction dstip dstport every execute group interface
64 %type
<opt
> protocol result rule srcip srcport logtag matching
65 %type
<opt
> matchopt nattag type doopt doing save syslog nothing
66 %type
<num
> saveopts saveopt typeopt
75 line: IPM_MATCH
'{' matching
'}' IPM_DO
'{' doing
'}' ';'
76 { build_action
($3); resetlexer
(); }
81 assign: YY_STR assigning YY_STR
';' { set_variable
($1, $3);
90 '=' { yyvarnext
= 1; }
95 | matchopt
',' matching
{ $1->o_next
= $3; $$
= $1; }
99 direction
{ $$
= $1; }
101 | dstport
{ $$
= $1; }
104 | interface
{ $$
= $1; }
105 | protocol
{ $$
= $1; }
106 | result
{ $$
= $1; }
109 | srcport
{ $$
= $1; }
110 | logtag
{ $$
= $1; }
111 | nattag
{ $$
= $1; }
117 | doopt
',' doing
{ $1->o_next
= $3; $$
= $1; }
123 | syslog
{ $$
= $1; }
124 | nothing
{ $$
= $1; }
128 IPM_DIRECTION
'=' IPM_IN
{ $$
= new_opt
(IPM_DIRECTION
);
129 $$
->o_num
= IPM_IN
; }
130 | IPM_DIRECTION
'=' IPM_OUT
{ $$
= new_opt
(IPM_DIRECTION
);
131 $$
->o_num
= IPM_OUT
; }
134 dstip: IPM_DSTIP
'=' ipv4
'/' YY_NUMBER
{ $$
= new_opt
(IPM_DSTIP
);
140 IPM_DSTPORT
'=' YY_NUMBER
{ $$
= new_opt
(IPM_DSTPORT
);
142 | IPM_DSTPORT
'=' YY_STR
{ $$
= new_opt
(IPM_DSTPORT
);
146 every: IPM_EVERY IPM_SECOND
{ $$
= new_opt
(IPM_SECOND
);
148 | IPM_EVERY YY_NUMBER IPM_SECONDS
{ $$
= new_opt
(IPM_SECOND
);
150 | IPM_EVERY IPM_PACKET
{ $$
= new_opt
(IPM_PACKET
);
152 | IPM_EVERY YY_NUMBER IPM_PACKETS
{ $$
= new_opt
(IPM_PACKET
);
156 group: IPM_GROUP
'=' YY_NUMBER
{ $$
= new_opt
(IPM_GROUP
);
158 | IPM_GROUP
'=' YY_STR
{ $$
= new_opt
(IPM_GROUP
);
163 IPM_INTERFACE
'=' YY_STR
{ $$
= new_opt
(IPM_INTERFACE
);
167 logtag: IPM_LOGTAG
'=' YY_NUMBER
{ $$
= new_opt
(IPM_LOGTAG
);
171 nattag: IPM_NATTAG
'=' YY_STR
{ $$
= new_opt
(IPM_NATTAG
);
176 IPM_PROTOCOL
'=' YY_NUMBER
{ $$
= new_opt
(IPM_PROTOCOL
);
178 | IPM_PROTOCOL
'=' YY_STR
{ $$
= new_opt
(IPM_PROTOCOL
);
179 $$
->o_num
= getproto
($3);
184 result: IPM_RESULT
'=' YY_STR
{ $$
= new_opt
(IPM_RESULT
);
188 rule: IPM_RULE
'=' YY_NUMBER
{ $$
= new_opt
(IPM_RULE
);
189 $$
->o_num
= YY_NUMBER
; }
192 srcip: IPM_SRCIP
'=' ipv4
'/' YY_NUMBER
{ $$
= new_opt
(IPM_SRCIP
);
198 IPM_SRCPORT
'=' YY_NUMBER
{ $$
= new_opt
(IPM_SRCPORT
);
200 | IPM_SRCPORT
'=' YY_STR
{ $$
= new_opt
(IPM_SRCPORT
);
204 type: IPM_TYPE
'=' typeopt
{ $$
= new_opt
(IPM_TYPE
);
209 IPM_IPF
{ $$
= IPL_MAGIC
; }
210 | IPM_NAT
{ $$
= IPL_MAGIC_NAT
; }
211 | IPM_STATE
{ $$
= IPL_MAGIC_STATE
; }
215 IPM_EXECUTE YY_STR
{ $$
= new_opt
(IPM_EXECUTE
);
219 save: IPM_SAVE saveopts YY_STR
{ $$
= new_opt
(IPM_SAVE
);
224 saveopts: { $$
= 0; }
225 | saveopt
{ $$
= $1; }
226 | saveopt
',' saveopts
{ $$
= $1 |
$3; }
230 IPM_RAW
{ $$
= IPMDO_SAVERAW
; }
233 syslog: IPM_SYSLOG
{ $$
= new_opt
(IPM_SYSLOG
); }
237 IPM_NOTHING
{ $$
= 0; }
240 ipv4: YY_NUMBER
'.' YY_NUMBER
'.' YY_NUMBER
'.' YY_NUMBER
241 { if
($1 > 255 ||
$3 > 255 ||
$5 > 255 ||
$7 > 255) {
242 yyerror("Invalid octet string for IP address");
245 $$.s_addr
= ($1 << 24) |
($3 << 16) |
($5 << 8) |
$7;
246 $$.s_addr
= htonl
($$.s_addr
);
249 static struct wordtab yywords
[] = {
250 { "body", IPM_BODY
},
251 { "direction", IPM_DIRECTION
},
253 { "dstip", IPM_DSTIP
},
254 { "dstport", IPM_DSTPORT
},
255 { "every", IPM_EVERY
},
256 { "execute", IPM_EXECUTE
},
257 { "group", IPM_GROUP
},
259 { "interface", IPM_INTERFACE
},
261 { "logtag", IPM_LOGTAG
},
262 { "match", IPM_MATCH
},
264 { "nattag", IPM_NATTAG
},
266 { "nothing", IPM_NOTHING
},
268 { "packet", IPM_PACKET
},
269 { "packets", IPM_PACKETS
},
270 { "protocol", IPM_PROTOCOL
},
271 { "result", IPM_RESULT
},
272 { "rule", IPM_RULE
},
273 { "save", IPM_SAVE
},
274 { "second", IPM_SECOND
},
275 { "seconds", IPM_SECONDS
},
276 { "srcip", IPM_SRCIP
},
277 { "srcport", IPM_SRCPORT
},
278 { "state", IPM_STATE
},
279 { "syslog", IPM_SYSLOG
},
280 { "with", IPM_WITH
},
284 static int macflags
[17][2] = {
285 { IPM_DIRECTION
, IPMAC_DIRECTION
},
286 { IPM_DSTIP
, IPMAC_DSTIP
},
287 { IPM_DSTPORT
, IPMAC_DSTPORT
},
288 { IPM_GROUP
, IPMAC_GROUP
},
289 { IPM_INTERFACE
, IPMAC_INTERFACE
},
290 { IPM_LOGTAG
, IPMAC_LOGTAG
},
291 { IPM_NATTAG
, IPMAC_NATTAG
},
292 { IPM_PACKET
, IPMAC_EVERY
},
293 { IPM_PROTOCOL
, IPMAC_PROTOCOL
},
294 { IPM_RESULT
, IPMAC_RESULT
},
295 { IPM_RULE
, IPMAC_RULE
},
296 { IPM_SECOND
, IPMAC_EVERY
},
297 { IPM_SRCIP
, IPMAC_SRCIP
},
298 { IPM_SRCPORT
, IPMAC_SRCPORT
},
299 { IPM_TYPE
, IPMAC_TYPE
},
300 { IPM_WITH
, IPMAC_WITH
},
304 static opt_t
*new_opt
(type
)
309 o
= (opt_t
*)malloc
(sizeof
(*o
));
311 o
->o_line
= yylineNum
;
313 o
->o_str
= (char *)0;
318 static void build_action
(olist
)
326 a
= (ipmon_action_t
*)calloc
(1, sizeof
(*a
));
329 while
((o
= olist
) != NULL
) {
331 * Check to see if the same comparator is being used more than
332 * once per matching statement.
334 for
(i
= 0; macflags
[i
][0]; i
++)
335 if
(macflags
[i
][0] == o
->o_type
)
337 if
(macflags
[i
][1] & a
->ac_mflag
) {
338 fprintf
(stderr
, "%s redfined on line %d\n",
339 yykeytostr
(o
->o_type
), yylineNum
);
340 if
(o
->o_str
!= NULL
)
347 a
->ac_mflag |
= macflags
[i
][1];
352 a
->ac_direction
= o
->o_num
;
355 a
->ac_dip
= o
->o_ip.s_addr
;
356 a
->ac_dmsk
= htonl
(0xffffffff << (32 - o
->o_num
));
359 a
->ac_dport
= htons
(o
->o_num
);
362 a
->ac_exec
= o
->o_str
;
364 if
(c
== '"'|| c
== '\'') {
365 if
(o
->o_str
[strlen
(o
->o_str
) - 1] == c
) {
366 a
->ac_run
= strdup
(o
->o_str
+ 1);
367 a
->ac_run
[strlen
(a
->ac_run
) - 1] ='\0';
369 a
->ac_run
= o
->o_str
;
371 a
->ac_run
= o
->o_str
;
375 a
->ac_iface
= o
->o_str
;
379 if
(o
->o_str
!= NULL
)
380 strncpy
(a
->ac_group
, o
->o_str
, FR_GROUPLEN
);
382 sprintf
(a
->ac_group
, "%d", o
->o_num
);
385 a
->ac_logtag
= o
->o_num
;
388 strncpy
(a
->ac_nattag
, o
->o_str
, sizeof
(a
->ac_nattag
));
391 a
->ac_packet
= o
->o_num
;
394 a
->ac_proto
= o
->o_num
;
397 a
->ac_rule
= o
->o_num
;
400 if
(!strcasecmp
(o
->o_str
, "pass"))
401 a
->ac_result
= IPMR_PASS
;
402 else if
(!strcasecmp
(o
->o_str
, "block"))
403 a
->ac_result
= IPMR_BLOCK
;
404 else if
(!strcasecmp
(o
->o_str
, "nomatch"))
405 a
->ac_result
= IPMR_NOMATCH
;
406 else if
(!strcasecmp
(o
->o_str
, "log"))
407 a
->ac_result
= IPMR_LOG
;
410 a
->ac_second
= o
->o_num
;
413 a
->ac_sip
= o
->o_ip.s_addr
;
414 a
->ac_smsk
= htonl
(0xffffffff << (32 - o
->o_num
));
417 a
->ac_sport
= htons
(o
->o_num
);
420 if
(a
->ac_savefile
!= NULL
) {
421 fprintf
(stderr
, "%s redfined on line %d\n",
422 yykeytostr
(o
->o_type
), yylineNum
);
425 a
->ac_savefile
= strdup
(o
->o_str
);
426 a
->ac_savefp
= fopen
(o
->o_str
, "a");
427 a
->ac_dflag |
= o
->o_num
& IPMDO_SAVERAW
;
430 if
(a
->ac_syslog
!= 0) {
431 fprintf
(stderr
, "%s redfined on line %d\n",
432 yykeytostr
(o
->o_type
), yylineNum
);
438 a
->ac_type
= o
->o_num
;
447 if
(o
->o_str
!= NULL
)
456 int check_action
(buf
, log
, opts
, lvl
)
470 ipl
= (iplog_t
*)buf
;
471 ipf
= (ipflog_t
*)(ipl
+1);
472 ip
= (ip_t
*)(ipf
+ 1);
473 tcp
= (tcphdr_t
*)((char *)ip
+ (IP_HL
(ip
) << 2));
475 for
(a
= alist
; a
!= NULL
; a
= a
->ac_next
) {
476 if
((a
->ac_mflag
& IPMAC_DIRECTION
) != 0) {
477 if
(a
->ac_direction
== IPM_IN
) {
478 if
((ipf
->fl_flags
& FR_INQUE
) == 0)
480 } else if
(a
->ac_direction
== IPM_OUT
) {
481 if
((ipf
->fl_flags
& FR_OUTQUE
) == 0)
486 if
((a
->ac_type
!= 0) && (a
->ac_type
!= ipl
->ipl_magic
))
489 if
((a
->ac_mflag
& IPMAC_EVERY
) != 0) {
490 gettimeofday
(&tv
, NULL
);
491 t1
= tv.tv_sec
- a
->ac_lastsec
;
492 if
(tv.tv_usec
<= a
->ac_lastusec
)
494 if
(a
->ac_second
!= 0) {
495 if
(t1
< a
->ac_second
)
497 a
->ac_lastsec
= tv.tv_sec
;
498 a
->ac_lastusec
= tv.tv_usec
;
501 if
(a
->ac_packet
!= 0) {
502 if
(a
->ac_pktcnt
== 0)
504 else if
(a
->ac_pktcnt
== a
->ac_packet
) {
514 if
((a
->ac_mflag
& IPMAC_DSTIP
) != 0) {
515 if
((ip
->ip_dst.s_addr
& a
->ac_dmsk
) != a
->ac_dip
)
519 if
((a
->ac_mflag
& IPMAC_DSTPORT
) != 0) {
520 if
(ip
->ip_p
!= IPPROTO_UDP
&& ip
->ip_p
!= IPPROTO_TCP
)
522 if
(tcp
->th_dport
!= a
->ac_dport
)
526 if
((a
->ac_mflag
& IPMAC_GROUP
) != 0) {
527 if
(strncmp
(a
->ac_group
, ipf
->fl_group
,
532 if
((a
->ac_mflag
& IPMAC_INTERFACE
) != 0) {
533 if
(strcmp
(a
->ac_iface
, ipf
->fl_ifname
))
537 if
((a
->ac_mflag
& IPMAC_PROTOCOL
) != 0) {
538 if
(a
->ac_proto
!= ip
->ip_p
)
542 if
((a
->ac_mflag
& IPMAC_RESULT
) != 0) {
543 if
((ipf
->fl_flags
& FF_LOGNOMATCH
) != 0) {
544 if
(a
->ac_result
!= IPMR_NOMATCH
)
546 } else if
(FR_ISPASS
(ipf
->fl_flags
)) {
547 if
(a
->ac_result
!= IPMR_PASS
)
549 } else if
(FR_ISBLOCK
(ipf
->fl_flags
)) {
550 if
(a
->ac_result
!= IPMR_BLOCK
)
552 } else
{ /* Log only */
553 if
(a
->ac_result
!= IPMR_LOG
)
558 if
((a
->ac_mflag
& IPMAC_RULE
) != 0) {
559 if
(a
->ac_rule
!= ipf
->fl_rule
)
563 if
((a
->ac_mflag
& IPMAC_SRCIP
) != 0) {
564 if
((ip
->ip_src.s_addr
& a
->ac_smsk
) != a
->ac_sip
)
568 if
((a
->ac_mflag
& IPMAC_SRCPORT
) != 0) {
569 if
(ip
->ip_p
!= IPPROTO_UDP
&& ip
->ip_p
!= IPPROTO_TCP
)
571 if
(tcp
->th_sport
!= a
->ac_sport
)
575 if
((a
->ac_mflag
& IPMAC_LOGTAG
) != 0) {
576 if
(a
->ac_logtag
!= ipf
->fl_logtag
)
580 if
((a
->ac_mflag
& IPMAC_NATTAG
) != 0) {
581 if
(strncmp
(a
->ac_nattag
, ipf
->fl_nattag.ipt_tag
,
589 * It matched so now execute the command
591 if
(a
->ac_syslog
!= 0) {
592 syslog
(lvl
, "%s", log
);
595 if
(a
->ac_savefp
!= NULL
) {
596 if
(a
->ac_dflag
& IPMDO_SAVERAW
)
597 fwrite
(ipl
, 1, ipl
->ipl_dsize
, a
->ac_savefp
);
599 fputs
(log
, a
->ac_savefp
);
602 if
(a
->ac_exec
!= NULL
) {
609 pi
= popen
(a
->ac_run
, "w");
611 fprintf
(pi
, "%s\n", log
);
612 if
((opts
& OPT_HEXHDR
) != 0) {
617 if
((opts
& OPT_HEXBODY
) != 0) {
618 dumphex
(pi
, 0, (char *)ip
,
638 static void free_action
(a
)
641 if
(a
->ac_savefile
!= NULL
) {
642 free
(a
->ac_savefile
);
643 a
->ac_savefile
= NULL
;
645 if
(a
->ac_savefp
!= NULL
) {
646 fclose
(a
->ac_savefp
);
649 if
(a
->ac_exec
!= NULL
) {
651 if
(a
->ac_run
== a
->ac_exec
)
655 if
(a
->ac_run
!= NULL
) {
659 if
(a
->ac_iface
!= NULL
) {
668 int load_config
(file
)
675 s
= getenv
("YYDEBUG");
681 while
((a
= alist
) != NULL
) {
688 (void) yysettab
(yywords
);
690 fp
= fopen
(file
, "r");
692 perror
("load_config:fopen:");