| /* |
| * Copyright (C) 2010 by Darren Reed. |
| * |
| * See the IPFILTER.LICENCE file for details on licencing. |
| */ |
| %{ |
| #include <sys/types.h> |
| #include <sys/ioctl.h> |
| #include "ipf.h" |
| #include "opts.h" |
| #include "kmem.h" |
| #include "ipscan_l.h" |
| #include "netinet/ip_scan.h" |
| |
| #define YYDEBUG 1 |
| |
| extern char *optarg; |
| extern void yyerror __P((char *)); |
| extern int yyparse __P((void)); |
| extern int yylex __P((void)); |
| extern int yydebug; |
| extern FILE *yyin; |
| extern int yylineNum; |
| extern void printbuf __P((char *, int, int)); |
| |
| |
| void printent __P((ipscan_t *)); |
| void showlist __P((void)); |
| int getportnum __P((char *)); |
| struct in_addr gethostip __P((char *)); |
| struct in_addr combine __P((int, int, int, int)); |
| char **makepair __P((char *, char *)); |
| void addtag __P((char *, char **, char **, struct action *)); |
| int cram __P((char *, char *)); |
| void usage __P((char *)); |
| int main __P((int, char **)); |
| |
| int opts = 0; |
| int fd = -1; |
| |
| |
| %} |
| |
| %union { |
| char *str; |
| char **astr; |
| u_32_t num; |
| struct in_addr ipa; |
| struct action act; |
| union i6addr ip6; |
| } |
| |
| %type <str> tag |
| %type <act> action redirect result |
| %type <ipa> ipaddr |
| %type <num> portnum |
| %type <astr> matchup onehalf twohalves |
| |
| %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 IPSL_START IPSL_STARTGROUP IPSL_CONTENT |
| |
| %token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE |
| |
| %% |
| file: line ';' |
| | assign ';' |
| | file line ';' |
| | file assign ';' |
| | YY_COMMENT |
| ; |
| |
| line: IPSL_START dline |
| | IPSL_STARTGROUP gline |
| | IPSL_CONTENT oline |
| ; |
| |
| dline: cline { resetlexer(); } |
| | sline { resetlexer(); } |
| | csline { resetlexer(); } |
| ; |
| |
| gline: YY_STR ':' glist '=' action |
| ; |
| |
| oline: cline |
| | sline |
| | csline |
| ; |
| |
| assign: YY_STR assigning YY_STR |
| { set_variable($1, $3); |
| resetlexer(); |
| free($1); |
| free($3); |
| yyvarnext = 0; |
| } |
| ; |
| |
| assigning: |
| '=' { yyvarnext = 1; } |
| ; |
| |
| cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); } |
| ; |
| |
| sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); } |
| ; |
| |
| csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); } |
| ; |
| |
| glist: YY_STR |
| | glist ',' YY_STR |
| ; |
| |
| tag: YY_STR { $$ = $1; } |
| ; |
| |
| matchup: |
| onehalf { $$ = $1; } |
| | twohalves { $$ = $1; } |
| ; |
| |
| action: result { $$.act_val = $1.act_val; |
| $$.act_ip = $1.act_ip; |
| $$.act_port = $1.act_port; } |
| | result IPSL_ELSE result { $$.act_val = $1.act_val; |
| $$.act_else = $3.act_val; |
| if ($1.act_val == IPSL_REDIRECT) { |
| $$.act_ip = $1.act_ip; |
| $$.act_port = $1.act_port; |
| } |
| if ($3.act_val == IPSL_REDIRECT) { |
| $$.act_eip = $3.act_eip; |
| $$.act_eport = $3.act_eport; |
| } |
| } |
| |
| result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; } |
| | IPSL_TRACK { $$.act_val = IPSL_TRACK; } |
| | redirect { $$.act_val = IPSL_REDIRECT; |
| $$.act_ip = $1.act_ip; |
| $$.act_port = $1.act_port; } |
| ; |
| |
| onehalf: |
| '(' YY_STR ')' { $$ = makepair($2, NULL); } |
| ; |
| |
| twohalves: |
| '(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); } |
| ; |
| |
| redirect: |
| IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3; |
| $$.act_port = 0; } |
| | IPSL_REDIRECT '(' ipaddr ',' portnum ')' |
| { $$.act_ip = $3; |
| $$.act_port = $5; } |
| ; |
| |
| |
| ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER |
| { $$ = combine($1,$3,$5,$7); } |
| | YY_STR { $$ = gethostip($1); |
| free($1); |
| } |
| ; |
| |
| portnum: |
| YY_NUMBER { $$ = htons($1); } |
| | YY_STR { $$ = getportnum($1); |
| free($1); |
| } |
| ; |
| |
| %% |
| |
| |
| static struct wordtab yywords[] = { |
| { "close", IPSL_CLOSE }, |
| { "content", IPSL_CONTENT }, |
| { "else", IPSL_ELSE }, |
| { "start-group", IPSL_STARTGROUP }, |
| { "redirect", IPSL_REDIRECT }, |
| { "start", IPSL_START }, |
| { "track", IPSL_TRACK }, |
| { NULL, 0 } |
| }; |
| |
| |
| int cram(dst, src) |
| char *dst; |
| char *src; |
| { |
| char c, *s, *t, *u; |
| int i, j, k; |
| |
| c = *src; |
| s = src + 1; |
| t = strchr(s, c); |
| *t = '\0'; |
| for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) { |
| c = *s++; |
| if (c == '\\') { |
| if (s >= t) |
| break; |
| j = k = 0; |
| do { |
| c = *s++; |
| if (j && (!ISDIGIT(c) || (c > '7') || |
| (k >= 248))) { |
| *u++ = k, i++; |
| j = k = 0; |
| s--; |
| break; |
| } |
| i++; |
| |
| if (ISALPHA(c) || (c > '7')) { |
| switch (c) |
| { |
| case 'n' : |
| *u++ = '\n'; |
| break; |
| case 'r' : |
| *u++ = '\r'; |
| break; |
| case 't' : |
| *u++ = '\t'; |
| break; |
| default : |
| *u++ = c; |
| break; |
| } |
| } else if (ISDIGIT(c)) { |
| j = 1; |
| k <<= 3; |
| k |= (c - '0'); |
| i--; |
| } else |
| *u++ = c; |
| } while ((i <= ISC_TLEN) && (s <= t) && (j > 0)); |
| } else |
| *u++ = c, i++; |
| } |
| return i; |
| } |
| |
| |
| void printent(isc) |
| ipscan_t *isc; |
| { |
| char buf[ISC_TLEN+1]; |
| u_char *u; |
| int i, j; |
| |
| buf[ISC_TLEN] = '\0'; |
| bcopy(isc->ipsc_ctxt, buf, ISC_TLEN); |
| printf("%s : (\"", isc->ipsc_tag); |
| printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0); |
| |
| bcopy(isc->ipsc_cmsk, buf, ISC_TLEN); |
| printf("\", \"%s\"), (\"", buf); |
| |
| printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0); |
| |
| bcopy(isc->ipsc_smsk, buf, ISC_TLEN); |
| printf("\", \"%s\") = ", buf); |
| |
| switch (isc->ipsc_action) |
| { |
| case ISC_A_TRACK : |
| printf("track"); |
| break; |
| case ISC_A_REDIRECT : |
| printf("redirect"); |
| printf("(%s", inet_ntoa(isc->ipsc_ip)); |
| if (isc->ipsc_port) |
| printf(",%d", isc->ipsc_port); |
| printf(")"); |
| break; |
| case ISC_A_CLOSE : |
| printf("close"); |
| break; |
| default : |
| break; |
| } |
| |
| if (isc->ipsc_else != ISC_A_NONE) { |
| printf(" else "); |
| switch (isc->ipsc_else) |
| { |
| case ISC_A_TRACK : |
| printf("track"); |
| break; |
| case ISC_A_REDIRECT : |
| printf("redirect"); |
| printf("(%s", inet_ntoa(isc->ipsc_eip)); |
| if (isc->ipsc_eport) |
| printf(",%d", isc->ipsc_eport); |
| printf(")"); |
| break; |
| case ISC_A_CLOSE : |
| printf("close"); |
| break; |
| default : |
| break; |
| } |
| } |
| printf("\n"); |
| |
| if (opts & OPT_DEBUG) { |
| for (u = (u_char *)isc, i = sizeof(*isc); i; ) { |
| printf("#"); |
| for (j = 32; (j > 0) && (i > 0); j--, i--) |
| printf("%s%02x", (j & 7) ? "" : " ", *u++); |
| printf("\n"); |
| } |
| } |
| if (opts & OPT_VERBOSE) { |
| printf("# hits %d active %d fref %d sref %d\n", |
| isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref, |
| isc->ipsc_sref); |
| } |
| } |
| |
| |
| void addtag(tstr, cp, sp, act) |
| char *tstr; |
| char **cp, **sp; |
| struct action *act; |
| { |
| ipscan_t isc, *iscp; |
| |
| bzero((char *)&isc, sizeof(isc)); |
| |
| strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag)); |
| isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0'; |
| |
| if (cp) { |
| isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]); |
| if (cp[1]) { |
| if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) { |
| fprintf(stderr, |
| "client text/mask strings different length\n"); |
| return; |
| } |
| } |
| } |
| |
| if (sp) { |
| isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]); |
| if (sp[1]) { |
| if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) { |
| fprintf(stderr, |
| "server text/mask strings different length\n"); |
| return; |
| } |
| } |
| } |
| |
| if (act->act_val == IPSL_CLOSE) { |
| isc.ipsc_action = ISC_A_CLOSE; |
| } else if (act->act_val == IPSL_TRACK) { |
| isc.ipsc_action = ISC_A_TRACK; |
| } else if (act->act_val == IPSL_REDIRECT) { |
| isc.ipsc_action = ISC_A_REDIRECT; |
| isc.ipsc_ip = act->act_ip; |
| isc.ipsc_port = act->act_port; |
| fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); |
| } |
| |
| if (act->act_else == IPSL_CLOSE) { |
| isc.ipsc_else = ISC_A_CLOSE; |
| } else if (act->act_else == IPSL_TRACK) { |
| isc.ipsc_else = ISC_A_TRACK; |
| } else if (act->act_else == IPSL_REDIRECT) { |
| isc.ipsc_else = ISC_A_REDIRECT; |
| isc.ipsc_eip = act->act_eip; |
| isc.ipsc_eport = act->act_eport; |
| fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); |
| } |
| |
| if (!(opts & OPT_DONOTHING)) { |
| iscp = &isc; |
| if (opts & OPT_REMOVE) { |
| if (ioctl(fd, SIOCRMSCA, &iscp) == -1) |
| perror("SIOCADSCA"); |
| } else { |
| if (ioctl(fd, SIOCADSCA, &iscp) == -1) |
| perror("SIOCADSCA"); |
| } |
| } |
| |
| if (opts & OPT_VERBOSE) |
| printent(&isc); |
| } |
| |
| |
| char **makepair(s1, s2) |
| char *s1, *s2; |
| { |
| char **a; |
| |
| a = malloc(sizeof(char *) * 2); |
| a[0] = s1; |
| a[1] = s2; |
| return a; |
| } |
| |
| |
| struct in_addr combine(a1, a2, a3, a4) |
| int a1, a2, a3, a4; |
| { |
| struct in_addr in; |
| |
| a1 &= 0xff; |
| in.s_addr = a1 << 24; |
| a2 &= 0xff; |
| in.s_addr |= (a2 << 16); |
| a3 &= 0xff; |
| in.s_addr |= (a3 << 8); |
| a4 &= 0xff; |
| in.s_addr |= a4; |
| in.s_addr = htonl(in.s_addr); |
| return in; |
| } |
| |
| |
| struct in_addr gethostip(host) |
| char *host; |
| { |
| struct hostent *hp; |
| struct in_addr in; |
| |
| in.s_addr = 0; |
| |
| hp = gethostbyname(host); |
| if (!hp) |
| return in; |
| bcopy(hp->h_addr, (char *)&in, sizeof(in)); |
| return in; |
| } |
| |
| |
| int getportnum(port) |
| char *port; |
| { |
| struct servent *s; |
| |
| s = getservbyname(port, "tcp"); |
| if (s == NULL) |
| return -1; |
| return s->s_port; |
| } |
| |
| |
| void showlist() |
| { |
| ipscanstat_t ipsc, *ipscp = &ipsc; |
| ipscan_t isc; |
| |
| if (ioctl(fd, SIOCGSCST, &ipscp) == -1) |
| perror("ioctl(SIOCGSCST)"); |
| else if (opts & OPT_SHOWLIST) { |
| while (ipsc.iscs_list != NULL) { |
| if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list, |
| sizeof(isc)) == -1) { |
| perror("kmemcpy"); |
| break; |
| } else { |
| printent(&isc); |
| ipsc.iscs_list = isc.ipsc_next; |
| } |
| } |
| } else { |
| printf("scan entries loaded\t%d\n", ipsc.iscs_entries); |
| printf("scan entries matches\t%ld\n", ipsc.iscs_acted); |
| printf("negative matches\t%ld\n", ipsc.iscs_else); |
| } |
| } |
| |
| |
| void usage(prog) |
| char *prog; |
| { |
| fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog); |
| fprintf(stderr, "\t%s [-dlv]\n", prog); |
| exit(1); |
| } |
| |
| |
| int main(argc, argv) |
| int argc; |
| char *argv[]; |
| { |
| FILE *fp = NULL; |
| int c; |
| |
| (void) yysettab(yywords); |
| |
| if (argc < 2) |
| usage(argv[0]); |
| |
| while ((c = getopt(argc, argv, "df:lnrsv")) != -1) |
| switch (c) |
| { |
| case 'd' : |
| opts |= OPT_DEBUG; |
| yydebug++; |
| break; |
| case 'f' : |
| if (!strcmp(optarg, "-")) |
| fp = stdin; |
| else { |
| fp = fopen(optarg, "r"); |
| if (!fp) { |
| perror("open"); |
| exit(1); |
| } |
| } |
| yyin = fp; |
| break; |
| case 'l' : |
| opts |= OPT_SHOWLIST; |
| break; |
| case 'n' : |
| opts |= OPT_DONOTHING; |
| break; |
| case 'r' : |
| opts |= OPT_REMOVE; |
| break; |
| case 's' : |
| opts |= OPT_STAT; |
| break; |
| case 'v' : |
| opts |= OPT_VERBOSE; |
| break; |
| } |
| |
| if (!(opts & OPT_DONOTHING)) { |
| fd = open(IPL_SCAN, O_RDWR); |
| if (fd == -1) { |
| perror("open(IPL_SCAN)"); |
| exit(1); |
| } |
| } |
| |
| if (fp != NULL) { |
| yylineNum = 1; |
| |
| while (!feof(fp)) |
| yyparse(); |
| fclose(fp); |
| exit(0); |
| } |
| |
| if (opts & (OPT_SHOWLIST|OPT_STAT)) { |
| showlist(); |
| exit(0); |
| } |
| exit(1); |
| } |