1 /*
   2  * Copyright (C) 1993-2005  by Darren Reed.
   3  * See the IPFILTER.LICENCE file for details on licencing.
   4  *
   5  * Copyright 2019 Joyent, Inc.
   6  */ 
   7 
   8 %{
   9 #include "ipf.h"
  10 #include <syslog.h>
  11 #include <uuid/uuid.h>
  12 #undef  OPT_NAT
  13 #undef  OPT_VERBOSE
  14 #include "ipmon_l.h"
  15 #include "ipmon.h"
  16 
  17 #define YYDEBUG 1
  18 
  19 extern  void    yyerror __P((char *));
  20 extern  int     yyparse __P((void));
  21 extern  int     yylex __P((void));
  22 extern  int     yydebug;
  23 extern  FILE    *yyin;
  24 extern  int     yylineNum;
  25 
  26 typedef struct  opt     {
  27         struct  opt     *o_next;
  28         int             o_line;
  29         int             o_type;
  30         int             o_num;
  31         char            *o_str;
  32         struct in_addr  o_ip;
  33 } opt_t;
  34 
  35 static  void    build_action __P((struct opt *));
  36 static  opt_t   *new_opt __P((int));
  37 static  void    free_action __P((ipmon_action_t *));
  38 
  39 static  ipmon_action_t  *alist = NULL;
  40 %}
  41 
  42 %union  {
  43         char    *str;
  44         u_32_t  num;
  45         struct in_addr  addr;
  46         struct opt      *opt;
  47         union   i6addr  ip6;
  48         uuid_t  uuid;
  49 }
  50 
  51 %token  <num>     YY_NUMBER YY_HEX
  52 %token  <str>     YY_STR
  53 %token  <ip6>     YY_IPV6
  54 %token  <uuid>    YY_UUID
  55 %token  YY_COMMENT 
  56 %token  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
  57 %token  YY_RANGE_OUT YY_RANGE_IN
  58 
  59 %token  IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
  60 %token  IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT
  61 %token  IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
  62 %token  IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
  63 %token  IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT
  64 %token  IPM_STATE IPM_NATTAG IPM_IPF
  65 %type   <addr> ipv4
  66 %type   <opt> direction dstip dstport every execute group interface
  67 %type   <opt> protocol result rule srcip srcport logtag matching
  68 %type   <opt> matchopt nattag type doopt doing save syslog nothing
  69 %type   <num> saveopts saveopt typeopt
  70 
  71 %%
  72 file:   line
  73         | assign
  74         | file line
  75         | file assign
  76         ;
  77 
  78 line:   IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';'
  79                                         { build_action($3); resetlexer(); }
  80         | IPM_COMMENT
  81         | YY_COMMENT
  82         ;
  83 
  84 assign: YY_STR assigning YY_STR ';'             { set_variable($1, $3);
  85                                                   resetlexer();
  86                                                   free($1);
  87                                                   free($3);
  88                                                 } 
  89         ;
  90 
  91 assigning:
  92         '='                                     { yyvarnext = 1; }
  93         ;
  94 
  95 matching:
  96         matchopt                                { $$ = $1; }
  97         | matchopt ',' matching                 { $1->o_next = $3; $$ = $1; }
  98         ;
  99 
 100 matchopt:
 101         direction                               { $$ = $1; }
 102         | dstip                                 { $$ = $1; }
 103         | dstport                               { $$ = $1; }
 104         | every                                 { $$ = $1; }
 105         | group                                 { $$ = $1; }
 106         | interface                             { $$ = $1; }
 107         | protocol                              { $$ = $1; }
 108         | result                                { $$ = $1; }
 109         | rule                                  { $$ = $1; }
 110         | srcip                                 { $$ = $1; }
 111         | srcport                               { $$ = $1; }
 112         | logtag                                { $$ = $1; }
 113         | nattag                                { $$ = $1; }
 114         | type                                  { $$ = $1; }
 115         ;
 116 
 117 doing:
 118         doopt                                   { $$ = $1; }
 119         | doopt ',' doing                       { $1->o_next = $3; $$ = $1; }
 120         ;
 121 
 122 doopt:
 123         execute                                 { $$ = $1; }
 124         | save                                  { $$ = $1; }
 125         | syslog                                { $$ = $1; }
 126         | nothing                               { $$ = $1; }
 127         ;
 128 
 129 direction:
 130         IPM_DIRECTION '=' IPM_IN                { $$ = new_opt(IPM_DIRECTION);
 131                                                   $$->o_num = IPM_IN; }
 132         | IPM_DIRECTION '=' IPM_OUT             { $$ = new_opt(IPM_DIRECTION);
 133                                                   $$->o_num = IPM_OUT; }
 134         ;
 135 
 136 dstip:  IPM_DSTIP '=' ipv4 '/' YY_NUMBER        { $$ = new_opt(IPM_DSTIP);
 137                                                   $$->o_ip = $3;
 138                                                   $$->o_num = $5; }
 139         ;
 140 
 141 dstport:
 142         IPM_DSTPORT '=' YY_NUMBER               { $$ = new_opt(IPM_DSTPORT);
 143                                                   $$->o_num = $3; }
 144         | IPM_DSTPORT '=' YY_STR                { $$ = new_opt(IPM_DSTPORT);
 145                                                   $$->o_str = $3; }
 146         ;
 147 
 148 every:  IPM_EVERY IPM_SECOND                    { $$ = new_opt(IPM_SECOND);
 149                                                   $$->o_num = 1; }
 150         | IPM_EVERY YY_NUMBER IPM_SECONDS       { $$ = new_opt(IPM_SECOND);
 151                                                   $$->o_num = $2; }
 152         | IPM_EVERY IPM_PACKET                  { $$ = new_opt(IPM_PACKET);
 153                                                   $$->o_num = 1; }
 154         | IPM_EVERY YY_NUMBER IPM_PACKETS       { $$ = new_opt(IPM_PACKET);
 155                                                   $$->o_num = $2; }
 156         ;
 157 
 158 group:  IPM_GROUP '=' YY_NUMBER                 { $$ = new_opt(IPM_GROUP);
 159                                                   $$->o_num = $3; }
 160         | IPM_GROUP '=' YY_STR                  { $$ = new_opt(IPM_GROUP);
 161                                                   $$->o_str = $3; }
 162         ;
 163 
 164 interface:
 165         IPM_INTERFACE '=' YY_STR                { $$ = new_opt(IPM_INTERFACE);
 166                                                   $$->o_str = $3; }
 167         ;
 168 
 169 logtag: IPM_LOGTAG '=' YY_NUMBER                { $$ = new_opt(IPM_LOGTAG);
 170                                                   $$->o_num = $3; }
 171         ;
 172 
 173 nattag: IPM_NATTAG '=' YY_STR                   { $$ = new_opt(IPM_NATTAG);
 174                                                   $$->o_str = $3; }
 175         ;
 176 
 177 protocol:
 178         IPM_PROTOCOL '=' YY_NUMBER              { $$ = new_opt(IPM_PROTOCOL);
 179                                                   $$->o_num = $3; }
 180         | IPM_PROTOCOL '=' YY_STR               { $$ = new_opt(IPM_PROTOCOL);
 181                                                   $$->o_num = getproto($3);
 182                                                   free($3);
 183                                                 }
 184         ;
 185 
 186 result: IPM_RESULT '=' YY_STR                   { $$ = new_opt(IPM_RESULT);
 187                                                   $$->o_str = $3; }
 188         ;
 189 
 190 rule:   IPM_RULE '=' YY_NUMBER                  { $$ = new_opt(IPM_RULE);
 191                                                   $$->o_num = YY_NUMBER; }
 192         ;
 193 
 194 srcip:  IPM_SRCIP '=' ipv4 '/' YY_NUMBER        { $$ = new_opt(IPM_SRCIP);
 195                                                   $$->o_ip = $3;
 196                                                   $$->o_num = $5; }
 197         ;
 198 
 199 srcport:
 200         IPM_SRCPORT '=' YY_NUMBER               { $$ = new_opt(IPM_SRCPORT);
 201                                                   $$->o_num = $3; }
 202         | IPM_SRCPORT '=' YY_STR                { $$ = new_opt(IPM_SRCPORT);
 203                                                   $$->o_str = $3; }
 204         ;
 205 
 206 type:   IPM_TYPE '=' typeopt                    { $$ = new_opt(IPM_TYPE);
 207                                                   $$->o_num = $3; }
 208         ;
 209 
 210 typeopt:
 211         IPM_IPF                                 { $$ = IPL_MAGIC; }
 212         | IPM_NAT                               { $$ = IPL_MAGIC_NAT; }
 213         | IPM_STATE                             { $$ = IPL_MAGIC_STATE; }
 214         ;
 215 
 216 execute:
 217         IPM_EXECUTE YY_STR                      { $$ = new_opt(IPM_EXECUTE);
 218                                                   $$->o_str = $2; }
 219         ;
 220 
 221 save:   IPM_SAVE saveopts YY_STR                { $$ = new_opt(IPM_SAVE);
 222                                                   $$->o_num = $2;
 223                                                   $$->o_str = $3; }
 224         ;
 225 
 226 saveopts:                                       { $$ = 0; }
 227         | saveopt                               { $$ = $1; }
 228         | saveopt ',' saveopts                  { $$ = $1 | $3; }
 229         ;
 230 
 231 saveopt:
 232         IPM_RAW                                 { $$ = IPMDO_SAVERAW; }
 233         ;
 234 
 235 syslog: IPM_SYSLOG                              { $$ = new_opt(IPM_SYSLOG); }
 236         ;
 237 
 238 nothing:
 239         IPM_NOTHING                             { $$ = 0; }
 240         ;
 241 
 242 ipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
 243                 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
 244                         yyerror("Invalid octet string for IP address");
 245                         return 0;
 246                   }
 247                   $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
 248                   $$.s_addr = htonl($$.s_addr);
 249                 }
 250 %%
 251 static  struct  wordtab yywords[] = {
 252         { "body",       IPM_BODY },
 253         { "direction",  IPM_DIRECTION },
 254         { "do",         IPM_DO },
 255         { "dstip",      IPM_DSTIP },
 256         { "dstport",    IPM_DSTPORT },
 257         { "every",      IPM_EVERY },
 258         { "execute",    IPM_EXECUTE },
 259         { "group",      IPM_GROUP },
 260         { "in",         IPM_IN },
 261         { "interface",  IPM_INTERFACE },
 262         { "ipf",        IPM_IPF },
 263         { "logtag",     IPM_LOGTAG },
 264         { "match",      IPM_MATCH },
 265         { "nat",        IPM_NAT },
 266         { "nattag",     IPM_NATTAG },
 267         { "no",         IPM_NO },
 268         { "nothing",    IPM_NOTHING },
 269         { "out",        IPM_OUT },
 270         { "packet",     IPM_PACKET },
 271         { "packets",    IPM_PACKETS },
 272         { "protocol",   IPM_PROTOCOL },
 273         { "result",     IPM_RESULT },
 274         { "rule",       IPM_RULE },
 275         { "save",       IPM_SAVE },
 276         { "raw",        IPM_RAW },
 277         { "second",     IPM_SECOND },
 278         { "seconds",    IPM_SECONDS },
 279         { "srcip",      IPM_SRCIP },
 280         { "srcport",    IPM_SRCPORT },
 281         { "state",      IPM_STATE },
 282         { "syslog",     IPM_SYSLOG },
 283         { "with",       IPM_WITH },
 284         { NULL,         0 }
 285 };
 286 
 287 static int macflags[17][2] = {
 288         { IPM_DIRECTION,        IPMAC_DIRECTION },
 289         { IPM_DSTIP,            IPMAC_DSTIP     },
 290         { IPM_DSTPORT,          IPMAC_DSTPORT   },
 291         { IPM_GROUP,            IPMAC_GROUP     },
 292         { IPM_INTERFACE,        IPMAC_INTERFACE },
 293         { IPM_LOGTAG,           IPMAC_LOGTAG    },
 294         { IPM_NATTAG,           IPMAC_NATTAG    },
 295         { IPM_PACKET,           IPMAC_EVERY     },
 296         { IPM_PROTOCOL,         IPMAC_PROTOCOL  },
 297         { IPM_RESULT,           IPMAC_RESULT    },
 298         { IPM_RULE,             IPMAC_RULE      },
 299         { IPM_SECOND,           IPMAC_EVERY     },
 300         { IPM_SRCIP,            IPMAC_SRCIP     },
 301         { IPM_SRCPORT,          IPMAC_SRCPORT   },
 302         { IPM_TYPE,             IPMAC_TYPE      },
 303         { IPM_WITH,             IPMAC_WITH      },
 304         { 0, 0 }
 305 };
 306 
 307 static opt_t *new_opt(type)
 308 int type;
 309 {
 310         opt_t *o;
 311 
 312         o = (opt_t *)malloc(sizeof(*o));
 313         if (o == NULL)
 314                 yyerror("sorry, out of memory");
 315         o->o_type = type;
 316         o->o_line = yylineNum;
 317         o->o_num = 0;
 318         o->o_str = (char *)0;
 319         o->o_next = NULL;
 320         return o;
 321 }
 322 
 323 static void build_action(olist)
 324 opt_t *olist;
 325 {
 326         ipmon_action_t *a;
 327         opt_t *o;
 328         char c;
 329         int i;
 330 
 331         a = (ipmon_action_t *)calloc(1, sizeof(*a));
 332         if (a == NULL)
 333                 return;
 334         while ((o = olist) != NULL) {
 335                 /*
 336                  * Check to see if the same comparator is being used more than
 337                  * once per matching statement.
 338                  */
 339                 for (i = 0; macflags[i][0]; i++)
 340                         if (macflags[i][0] == o->o_type)
 341                                 break;
 342                 if (macflags[i][1] & a->ac_mflag) {
 343                         fprintf(stderr, "%s redfined on line %d\n",
 344                                 yykeytostr(o->o_type), yylineNum);
 345                         if (o->o_str != NULL)
 346                                 free(o->o_str);
 347                         olist = o->o_next;
 348                         free(o);
 349                         continue;
 350                 }
 351 
 352                 a->ac_mflag |= macflags[i][1];
 353 
 354                 switch (o->o_type)
 355                 {
 356                 case IPM_DIRECTION :
 357                         a->ac_direction = o->o_num;
 358                         break;
 359                 case IPM_DSTIP :
 360                         a->ac_dip = o->o_ip.s_addr;
 361                         a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
 362                         break;
 363                 case IPM_DSTPORT :
 364                         a->ac_dport = htons(o->o_num);
 365                         break;
 366                 case IPM_EXECUTE :
 367                         a->ac_exec = o->o_str;
 368                         c = *o->o_str;
 369                         if (c== '"'|| c == '\'') {
 370                                 if (o->o_str[strlen(o->o_str) - 1] == c) {
 371                                         a->ac_run = strdup(o->o_str + 1);
 372                                         a->ac_run[strlen(a->ac_run) - 1] ='\0';
 373                                 } else
 374                                         a->ac_run = o->o_str;
 375                         } else
 376                                 a->ac_run = o->o_str;
 377                         o->o_str = NULL;
 378                         break;
 379                 case IPM_INTERFACE :
 380                         a->ac_iface = o->o_str;
 381                         o->o_str = NULL;
 382                         break;
 383                 case IPM_GROUP : 
 384                         if (o->o_str != NULL)
 385                                 strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
 386                         else
 387                                 sprintf(a->ac_group, "%d", o->o_num);
 388                         break;
 389                 case IPM_LOGTAG :
 390                         a->ac_logtag = o->o_num;
 391                         break;
 392                 case IPM_NATTAG :
 393                         strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
 394                         break;
 395                 case IPM_PACKET :
 396                         a->ac_packet = o->o_num;
 397                         break;
 398                 case IPM_PROTOCOL :
 399                         a->ac_proto = o->o_num;
 400                         break;
 401                 case IPM_RULE :
 402                         a->ac_rule = o->o_num;
 403                         break;
 404                 case IPM_RESULT :
 405                         if (!strcasecmp(o->o_str, "pass"))
 406                                 a->ac_result = IPMR_PASS;
 407                         else if (!strcasecmp(o->o_str, "block"))
 408                                 a->ac_result = IPMR_BLOCK;
 409                         else if (!strcasecmp(o->o_str, "nomatch"))
 410                                 a->ac_result = IPMR_NOMATCH;
 411                         else if (!strcasecmp(o->o_str, "log"))
 412                                 a->ac_result = IPMR_LOG;
 413                         break;
 414                 case IPM_SECOND :
 415                         a->ac_second = o->o_num;
 416                         break;
 417                 case IPM_SRCIP :
 418                         a->ac_sip = o->o_ip.s_addr;
 419                         a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
 420                         break;
 421                 case IPM_SRCPORT :
 422                         a->ac_sport = htons(o->o_num);
 423                         break;
 424                 case IPM_SAVE :
 425                         if (a->ac_savefile != NULL) {
 426                                 fprintf(stderr, "%s redfined on line %d\n",
 427                                         yykeytostr(o->o_type), yylineNum);
 428                                 break;
 429                         }
 430                         a->ac_savefile = strdup(o->o_str);
 431                         a->ac_savefp = fopen(o->o_str, "a");
 432                         a->ac_dflag |= o->o_num & IPMDO_SAVERAW;
 433                         break;
 434                 case IPM_SYSLOG :
 435                         if (a->ac_syslog != 0) {
 436                                 fprintf(stderr, "%s redfined on line %d\n",
 437                                         yykeytostr(o->o_type), yylineNum);
 438                                 break;
 439                         }
 440                         a->ac_syslog = 1;
 441                         break;
 442                 case IPM_TYPE :
 443                         a->ac_type = o->o_num;
 444                         break;
 445                 case IPM_WITH :
 446                         break;
 447                 default :
 448                         break;
 449                 }
 450 
 451                 olist = o->o_next;
 452                 if (o->o_str != NULL)
 453                         free(o->o_str);
 454                 free(o);
 455         }
 456         a->ac_next = alist;
 457         alist = a;
 458 }
 459 
 460 
 461 int check_action(buf, log, opts, lvl)
 462 char *buf, *log;
 463 int opts, lvl;
 464 {
 465         ipmon_action_t *a;
 466         struct timeval tv;
 467         ipflog_t *ipf;
 468         tcphdr_t *tcp;
 469         iplog_t *ipl;
 470         int matched;
 471         u_long t1;
 472         ip_t *ip;
 473 
 474         matched = 0;
 475         ipl = (iplog_t *)buf;
 476         ipf = (ipflog_t *)(ipl +1);
 477         ip = (ip_t *)(ipf + 1);
 478         tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
 479 
 480         for (a = alist; a != NULL; a = a->ac_next) {
 481                 if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
 482                         if (a->ac_direction == IPM_IN) {
 483                                 if ((ipf->fl_flags & FR_INQUE) == 0)
 484                                         continue;
 485                         } else if (a->ac_direction == IPM_OUT) {
 486                                 if ((ipf->fl_flags & FR_OUTQUE) == 0)
 487                                         continue;
 488                         }
 489                 }
 490 
 491                 if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic))
 492                         continue;
 493 
 494                 if ((a->ac_mflag & IPMAC_EVERY) != 0) {
 495                         gettimeofday(&tv, NULL);
 496                         t1 = tv.tv_sec - a->ac_lastsec;
 497                         if (tv.tv_usec <= a->ac_lastusec)
 498                                 t1--;
 499                         if (a->ac_second != 0) {
 500                                 if (t1 < a->ac_second)
 501                                         continue;
 502                                 a->ac_lastsec = tv.tv_sec;
 503                                 a->ac_lastusec = tv.tv_usec;
 504                         }
 505 
 506                         if (a->ac_packet != 0) {
 507                                 if (a->ac_pktcnt == 0)
 508                                         a->ac_pktcnt++;
 509                                 else if (a->ac_pktcnt == a->ac_packet) {
 510                                         a->ac_pktcnt = 0;
 511                                         continue;
 512                                 } else {
 513                                         a->ac_pktcnt++;
 514                                         continue;
 515                                 }
 516                         }
 517                 }
 518 
 519                 if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
 520                         if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip)
 521                                 continue;
 522                 }
 523 
 524                 if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
 525                         if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
 526                                 continue;
 527                         if (tcp->th_dport != a->ac_dport)
 528                                 continue;
 529                 }
 530 
 531                 if ((a->ac_mflag & IPMAC_GROUP) != 0) {
 532                         if (strncmp(a->ac_group, ipf->fl_group,
 533                                     FR_GROUPLEN) != 0)
 534                                 continue;
 535                 }
 536 
 537                 if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
 538                         if (strcmp(a->ac_iface, ipf->fl_ifname))
 539                                 continue;
 540                 }
 541 
 542                 if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
 543                         if (a->ac_proto != ip->ip_p)
 544                                 continue;
 545                 }
 546 
 547                 if ((a->ac_mflag & IPMAC_RESULT) != 0) {
 548                         if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
 549                                 if (a->ac_result != IPMR_NOMATCH)
 550                                         continue;
 551                         } else if (FR_ISPASS(ipf->fl_flags)) {
 552                                 if (a->ac_result != IPMR_PASS)
 553                                         continue;
 554                         } else if (FR_ISBLOCK(ipf->fl_flags)) {
 555                                 if (a->ac_result != IPMR_BLOCK)
 556                                         continue;
 557                         } else {        /* Log only */
 558                                 if (a->ac_result != IPMR_LOG)
 559                                         continue;
 560                         }
 561                 }
 562 
 563                 if ((a->ac_mflag & IPMAC_RULE) != 0) {
 564                         if (a->ac_rule != ipf->fl_rule)
 565                                 continue;
 566                 }
 567 
 568                 if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
 569                         if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip)
 570                                 continue;
 571                 }
 572 
 573                 if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
 574                         if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
 575                                 continue;
 576                         if (tcp->th_sport != a->ac_sport)
 577                                 continue;
 578                 }
 579 
 580                 if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
 581                         if (a->ac_logtag != ipf->fl_logtag)
 582                                 continue;
 583                 }
 584 
 585                 if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
 586                         if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
 587                                     IPFTAG_LEN) != 0)
 588                                 continue;
 589                 }
 590 
 591                 matched = 1;
 592 
 593                 /*
 594                  * It matched so now execute the command
 595                  */
 596                 if (a->ac_syslog != 0) {
 597                         syslog(lvl, "%s", log);
 598                 }
 599 
 600                 if (a->ac_savefp != NULL) {
 601                         if (a->ac_dflag & IPMDO_SAVERAW)
 602                                 fwrite(ipl, 1, ipl->ipl_dsize, a->ac_savefp);
 603                         else
 604                                 fputs(log, a->ac_savefp);
 605                 }
 606 
 607                 if (a->ac_exec != NULL) {
 608                         switch (fork())
 609                         {
 610                         case 0 :
 611                         {
 612                                 FILE *pi;
 613 
 614                                 pi = popen(a->ac_run, "w");
 615                                 if (pi != NULL) {
 616                                         fprintf(pi, "%s\n", log);
 617                                         if ((opts & OPT_HEXHDR) != 0) {
 618                                                 dumphex(pi, 0, buf,
 619                                                         sizeof(*ipl) +
 620                                                         sizeof(*ipf));
 621                                         }
 622                                         if ((opts & OPT_HEXBODY) != 0) {
 623                                                 dumphex(pi, 0, (char *)ip,
 624                                                         ipf->fl_hlen +
 625                                                         ipf->fl_plen);
 626                                         }
 627                                         pclose(pi);
 628                                 }
 629                                 exit(1);
 630                         }
 631                         case -1 :
 632                                 break;
 633                         default :
 634                                 break;
 635                         }
 636                 }
 637         }
 638 
 639         return matched;
 640 }
 641 
 642 
 643 static void free_action(a)
 644 ipmon_action_t *a;
 645 {
 646         if (a->ac_savefile != NULL) {
 647                 free(a->ac_savefile);
 648                 a->ac_savefile = NULL;
 649         }
 650         if (a->ac_savefp != NULL) {
 651                 fclose(a->ac_savefp);
 652                 a->ac_savefp = NULL;
 653         }
 654         if (a->ac_exec != NULL) {
 655                 free(a->ac_exec);
 656                 if (a->ac_run == a->ac_exec)
 657                         a->ac_run = NULL;
 658                 a->ac_exec = NULL;
 659         }
 660         if (a->ac_run != NULL) {
 661                 free(a->ac_run);
 662                 a->ac_run = NULL;
 663         }
 664         if (a->ac_iface != NULL) {
 665                 free(a->ac_iface);
 666                 a->ac_iface = NULL;
 667         }
 668         a->ac_next = NULL;
 669         free(a);
 670 }
 671 
 672 
 673 int load_config(file)
 674 char *file;
 675 {
 676         ipmon_action_t *a;
 677         FILE *fp;
 678         char *s;
 679 
 680         s = getenv("YYDEBUG");
 681         if (s != NULL)
 682                 yydebug = atoi(s);
 683         else
 684                 yydebug = 0;
 685 
 686         while ((a = alist) != NULL) {
 687                 alist = a->ac_next;
 688                 free_action(a);
 689         }
 690 
 691         yylineNum = 1;
 692 
 693         (void) yysettab(yywords);
 694 
 695         fp = fopen(file, "r");
 696         if (!fp) {
 697                 perror("load_config:fopen:");
 698                 return -1;
 699         }
 700         yyin = fp;
 701         while (!feof(fp))
 702                 yyparse();
 703         fclose(fp);
 704         return 0;
 705 }