ipmon_y.y revision 7c478bd95313f5f23a4c958a745db2134aa03244
%{
#include "ipf.h"
#undef OPT_NAT
#undef OPT_VERBOSE
#include "ipmon_l.h"
#include "ipmon.h"
#define YYDEBUG 1
extern void yyerror __P((char *));
extern int yyparse __P((void));
extern int yylex __P((void));
extern int yydebug;
extern FILE *yyin;
extern int yylineNum;
typedef struct opt {
struct opt *o_next;
int o_line;
int o_type;
int o_num;
char *o_str;
struct in_addr o_ip;
} opt_t;
static void build_action __P((struct opt *));
static opt_t *new_opt __P((int));
static action_t *alist = NULL;
%}
%union {
char *str;
u_32_t num;
struct in_addr addr;
struct opt *opt;
union i6addr ip6;
}
%token <num> YY_NUMBER YY_HEX
%token <str> YY_STR
%token YY_COMMENT
%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
%token YY_RANGE_OUT YY_RANGE_IN
%token <ip6> YY_IPV6
%token IPM_ACTION IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
%token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT
%token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
%token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_TAG IPM_YES
%type <addr> ipv4
%type <opt> direction dstip dstport every execute group interface option
%type <opt> options protocol result rule srcip srcport tag
%%
file: line
| assign
| file line
| file assign
;
line: IPM_ACTION '{' options '}' ';' { build_action($3); resetlexer(); }
| IPM_COMMENT
;
assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
resetlexer();
free($1);
free($3);
}
;
assigning:
'=' { yyvarnext = 1; }
;
options:
option { $$ = $1; }
| option ',' options { $1->o_next = $3; $$ = $1; }
;
option: direction { $$ = $1; }
| dstip { $$ = $1; }
| dstport { $$ = $1; }
| every { $$ = $1; }
| execute { $$ = $1; }
| group { $$ = $1; }
| interface { $$ = $1; }
| protocol { $$ = $1; }
| result { $$ = $1; }
| rule { $$ = $1; }
| srcip { $$ = $1; }
| srcport { $$ = $1; }
| tag { $$ = $1; }
;
direction:
IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION);
$$->o_num = IPM_IN; }
| IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION);
$$->o_num = IPM_OUT; }
;
dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP);
$$->o_ip = $3;
$$->o_num = $5; }
;
dstport:
IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT);
$$->o_num = $3; }
| IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT);
$$->o_str = $3; }
;
every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND);
$$->o_num = 1; }
| IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND);
$$->o_num = $2; }
| IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET);
$$->o_num = 1; }
| IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET);
$$->o_num = $2; }
;
execute:
IPM_EXECUTE '=' YY_STR { $$ = new_opt(IPM_EXECUTE);
$$->o_str = $3; }
;
group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP);
$$->o_num = $3; }
| IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP);
$$->o_str = $3; }
;
interface:
IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE);
$$->o_str = $3; }
;
protocol:
IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL);
$$->o_num = $3; }
| IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL);
$$->o_num = getproto($3);
free($3);
}
;
result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT);
$$->o_str = $3; }
;
rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE);
$$->o_num = YY_NUMBER; }
;
srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP);
$$->o_ip = $3;
$$->o_num = $5; }
;
srcport:
IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT);
$$->o_num = $3; }
| IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT);
$$->o_str = $3; }
;
tag: IPM_TAG '=' YY_NUMBER { $$ = new_opt(IPM_TAG);
$$->o_num = $3; }
;
ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
yyerror("Invalid octet string for IP address");
return 0;
}
$$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
$$.s_addr = htonl($$.s_addr);
}
%%
static struct wordtab yywords[] = {
{ "action", IPM_ACTION },
{ "body", IPM_BODY },
{ "direction", IPM_DIRECTION },
{ "dstip", IPM_DSTIP },
{ "dstport", IPM_DSTPORT },
{ "every", IPM_EVERY },
{ "execute", IPM_EXECUTE },
{ "group", IPM_GROUP },
{ "in", IPM_IN },
{ "interface", IPM_INTERFACE },
{ "no", IPM_NO },
{ "out", IPM_OUT },
{ "packet", IPM_PACKET },
{ "packets", IPM_PACKETS },
{ "protocol", IPM_PROTOCOL },
{ "result", IPM_RESULT },
{ "rule", IPM_RULE },
{ "second", IPM_SECOND },
{ "seconds", IPM_SECONDS },
{ "srcip", IPM_SRCIP },
{ "srcport", IPM_SRCPORT },
{ "tag", IPM_TAG },
{ "yes", IPM_YES },
{ NULL, 0 }
};
static int macflags[15][2] = {
{ IPM_DIRECTION, IPMAC_DIRECTION },
{ IPM_DSTIP, IPMAC_DSTIP },
{ IPM_DSTPORT, IPMAC_DSTPORT },
{ IPM_EXECUTE, IPMAC_EXECUTE },
{ IPM_GROUP, IPMAC_GROUP },
{ IPM_INTERFACE, IPMAC_INTERFACE },
{ IPM_PACKET, IPMAC_EVERY },
{ IPM_PROTOCOL, IPMAC_PROTOCOL },
{ IPM_RESULT, IPMAC_RESULT },
{ IPM_RULE, IPMAC_RULE },
{ IPM_SECOND, IPMAC_EVERY },
{ IPM_SRCIP, IPMAC_SRCIP },
{ IPM_SRCPORT, IPMAC_SRCPORT },
{ IPM_TAG, IPMAC_TAG },
{ 0, 0 }
};
static opt_t *new_opt(type)
int type;
{
opt_t *o;
o = (opt_t *)malloc(sizeof(*o));
o->o_type = type;
o->o_line = yylineNum;
o->o_num = 0;
o->o_str = (char *)0;
return o;
}
static void build_action(olist)
opt_t *olist;
{
action_t *a;
opt_t *o;
u_32_t m;
char c;
int i;
a = (action_t *)calloc(1, sizeof(*a));
if (!a)
return;
while ((o = olist)) {
for (i = 0; macflags[i][0]; i++)
if (macflags[i][0] == o->o_type)
break;
if (macflags[i][1] & a->ac_mflag) {
fprintf(stderr, "%s redfined on line %d\n",
yykeytostr(o->o_type), yylineNum);
if (o->o_str != NULL)
free(o->o_str);
olist = o->o_next;
free(o);
continue;
}
a->ac_mflag |= macflags[i][1];
switch (o->o_type)
{
case IPM_DIRECTION :
a->ac_direction = o->o_num;
break;
case IPM_DSTIP :
a->ac_dip = o->o_ip.s_addr;
for (i = o->o_num, m = 0; i; i--) {
m >>= 1;
m |= 0x80000000;
}
a->ac_dmsk = htonl(m);
break;
case IPM_DSTPORT :
a->ac_dport = htons(o->o_num);
break;
case IPM_EXECUTE :
a->ac_exec = o->o_str;
c = *o->o_str;
if (c== '"'|| c == '\'') {
if (o->o_str[strlen(o->o_str) - 1] == c) {
a->ac_run = strdup(o->o_str + 1);
a->ac_run[strlen(a->ac_run) - 1] ='\0';
} else
a->ac_run = o->o_str;
} else
a->ac_run = o->o_str;
o->o_str = NULL;
break;
case IPM_INTERFACE :
a->ac_iface = o->o_str;
o->o_str = NULL;
break;
case IPM_GROUP :
if (o->o_str != NULL)
strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
else
sprintf(a->ac_group, "%d", o->o_num);
break;
case IPM_PACKET :
a->ac_packet = o->o_num;
break;
case IPM_PROTOCOL :
a->ac_proto = o->o_num;
break;
case IPM_RULE :
a->ac_rule = o->o_num;
break;
case IPM_RESULT :
if (!strcasecmp(o->o_str, "pass"))
a->ac_result = IPMR_PASS;
else if (!strcasecmp(o->o_str, "block"))
a->ac_result = IPMR_BLOCK;
else if (!strcasecmp(o->o_str, "short"))
a->ac_result = IPMR_SHORT;
else if (!strcasecmp(o->o_str, "nomatch"))
a->ac_result = IPMR_NOMATCH;
else if (!strcasecmp(o->o_str, "log"))
a->ac_result = IPMR_LOG;
break;
case IPM_SECOND :
a->ac_second = o->o_num;
break;
case IPM_SRCIP :
a->ac_sip = o->o_ip.s_addr;
for (i = o->o_num, m = 0; i; i--) {
m >>= 1;
m |= 0x80000000;
}
a->ac_smsk = htonl(m);
break;
case IPM_SRCPORT :
a->ac_sport = htons(o->o_num);
break;
case IPM_TAG :
a->ac_tag = o->o_num;
break;
default :
break;
}
olist = o->o_next;
if (o->o_str != NULL)
free(o->o_str);
free(o);
}
a->a_next = alist;
alist = a;
}
void check_action(buf, opts, log)
char *buf;
int opts;
char *log;
{
struct timeval tv;
ipflog_t *ipf;
tcphdr_t *tcp;
iplog_t *ipl;
action_t *a;
u_long t1;
ip_t *ip;
ipl = (iplog_t *)buf;
ipf = (ipflog_t *)(ipl +1);
ip = (ip_t *)(ipf + 1);
tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
for (a = alist; a; a = a->a_next) {
if (a->ac_mflag & IPMAC_DIRECTION) {
if (a->ac_direction == IPM_IN) {
if (!(ipf->fl_flags & FR_INQUE))
continue;
} else if (a->ac_direction == IPM_OUT) {
if (!(ipf->fl_flags & FR_OUTQUE))
continue;
}
}
if (a->ac_mflag & IPMAC_EVERY) {
gettimeofday(&tv, NULL);
t1 = tv.tv_sec - a->ac_lastsec;
if (tv.tv_usec <= a->ac_lastusec)
t1--;
if (a->ac_second) {
if (t1 < a->ac_second)
continue;
a->ac_lastsec = tv.tv_sec;
a->ac_lastusec = tv.tv_usec;
}
if (a->ac_packet) {
if (!a->ac_pktcnt)
a->ac_pktcnt++;
else if (a->ac_pktcnt == a->ac_packet) {
a->ac_pktcnt = 0;
continue;
} else {
a->ac_pktcnt++;
continue;
}
}
}
if (a->ac_mflag & IPMAC_DSTIP) {
if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip)
continue;
}
if (a->ac_mflag & IPMAC_DSTPORT) {
if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
continue;
if (tcp->th_dport != a->ac_dport)
continue;
}
if (a->ac_mflag & IPMAC_GROUP) {
if (strncmp(a->ac_group, ipf->fl_group,
FR_GROUPLEN) != 0)
continue;
}
if (a->ac_mflag & IPMAC_INTERFACE) {
if (strcmp(a->ac_iface, ipf->fl_ifname))
continue;
}
if (a->ac_mflag & IPMAC_PROTOCOL) {
if (a->ac_proto != ip->ip_p)
continue;
}
if (a->ac_mflag & IPMAC_RESULT) {
if (ipf->fl_lflags & FI_SHORT) {
if (a->ac_result != IPMR_SHORT)
continue;
} else if (FR_ISPASS(ipf->fl_flags)) {
if (a->ac_result != IPMR_PASS)
continue;
} else if (FR_ISBLOCK(ipf->fl_flags)) {
if (a->ac_result != IPMR_BLOCK)
continue;
} else if (ipf->fl_flags & FF_LOGNOMATCH) {
if (a->ac_result != IPMR_NOMATCH)
continue;
} else { /* Log only */
if (a->ac_result != IPMR_LOG)
continue;
}
}
if (a->ac_mflag & IPMAC_RULE) {
if (a->ac_rule != ipf->fl_rule)
continue;
}
if (a->ac_mflag & IPMAC_SRCIP) {
if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip)
continue;
}
if (a->ac_mflag & IPMAC_SRCPORT) {
if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
continue;
if (tcp->th_sport != a->ac_sport)
continue;
}
if (a->ac_mflag & IPMAC_TAG) {
if (a->ac_tag != ipf->fl_tag)
continue;
}
/*
* It matched so now execute the command
*/
if (a->ac_exec) {
switch (fork())
{
case 0 :
{
FILE *pi;
pi = popen(a->ac_run, "w");
if (pi) {
fprintf(pi, "%s\n", log);
if (opts & OPT_HEXHDR) {
dumphex(pi, 0, buf,
sizeof(*ipl) +
sizeof(*ipf));
}
if (opts & OPT_HEXBODY) {
dumphex(pi, 0, (char *)ip,
ipf->fl_hlen +
ipf->fl_plen);
}
pclose(pi);
}
exit(1);
}
case -1 :
break;
default :
break;
}
}
}
}
int load_config(file)
char *file;
{
FILE *fp;
yylineNum = 0;
(void) yysettab(yywords);
fp = fopen(file, "r");
if (!fp) {
perror("load_config:fopen:");
return -1;
}
yyin = fp;
while (!feof(fp))
yyparse();
fclose(fp);
return 0;
}