1
2 /*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7 %{
8 #include <sys/types.h>
9 #include <sys/ioctl.h>
10 #include "ipf.h"
11 #include "opts.h"
12 #include "kmem.h"
13 #include "ipscan_l.h"
14 #include "netinet/ip_scan.h"
15 #include <ctype.h>
16
17 #define YYDEBUG 1
18
19 extern char *optarg;
20 extern void yyerror(char *);
21 extern int yyparse(void);
22 extern int yylex(void);
23 extern int yydebug;
24 extern FILE *yyin;
25 extern int yylineNum;
26 extern void printbuf(char *, int, int);
27
28
29 void printent(ipscan_t *);
30 void showlist(void);
31 int getportnum(char *);
32 struct in_addr gethostip(char *);
33 struct in_addr combine(int, int, int, int);
34 char **makepair(char *, char *);
35 void addtag(char *, char **, char **, struct action *);
36 int cram(char *, char *);
37 void usage(char *);
38 int main(int, char **);
39
40 int opts = 0;
41 int fd = -1;
42
43
44 %}
45
46 %union {
47 char *str;
48 char **astr;
49 u_32_t num;
50 struct in_addr ipa;
51 struct action act;
52 union i6addr ip6;
53 }
54
55 %type <str> tag
56 %type <act> action redirect result
57 %type <ipa> ipaddr
58 %type <num> portnum
59 %type <astr> matchup onehalf twohalves
60
61 %token <num> YY_NUMBER YY_HEX
62 %token <str> YY_STR
63 %token YY_COMMENT
64 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
65 %token YY_RANGE_OUT YY_RANGE_IN
66 %token <ip6> YY_IPV6
67 %token IPSL_START IPSL_STARTGROUP IPSL_CONTENT
68
69 %token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE
70
71 %%
72 file: line ';'
73 | assign ';'
74 | file line ';'
75 | file assign ';'
76 | YY_COMMENT
77 ;
78
79 line: IPSL_START dline
80 | IPSL_STARTGROUP gline
81 | IPSL_CONTENT oline
82 ;
83
84 dline: cline { resetlexer(); }
85 | sline { resetlexer(); }
86 | csline { resetlexer(); }
87 ;
88
89 gline: YY_STR ':' glist '=' action
90 ;
91
92 oline: cline
93 | sline
94 | csline
95 ;
96
97 assign: YY_STR assigning YY_STR
98 { set_variable($1, $3);
99 resetlexer();
100 free($1);
101 free($3);
102 yyvarnext = 0;
103 }
104 ;
105
106 assigning:
107 '=' { yyvarnext = 1; }
108 ;
109
110 cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); }
111 ;
112
113 sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); }
114 ;
115
116 csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); }
117 ;
118
119 glist: YY_STR
120 | glist ',' YY_STR
121 ;
122
123 tag: YY_STR { $$ = $1; }
124 ;
125
126 matchup:
127 onehalf { $$ = $1; }
128 | twohalves { $$ = $1; }
129 ;
130
131 action: result { $$.act_val = $1.act_val;
132 $$.act_ip = $1.act_ip;
133 $$.act_port = $1.act_port; }
134 | result IPSL_ELSE result { $$.act_val = $1.act_val;
135 $$.act_else = $3.act_val;
136 if ($1.act_val == IPSL_REDIRECT) {
137 $$.act_ip = $1.act_ip;
138 $$.act_port = $1.act_port;
139 }
140 if ($3.act_val == IPSL_REDIRECT) {
141 $$.act_eip = $3.act_eip;
142 $$.act_eport = $3.act_eport;
143 }
144 }
145
146 result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; }
147 | IPSL_TRACK { $$.act_val = IPSL_TRACK; }
148 | redirect { $$.act_val = IPSL_REDIRECT;
149 $$.act_ip = $1.act_ip;
150 $$.act_port = $1.act_port; }
151 ;
152
153 onehalf:
154 '(' YY_STR ')' { $$ = makepair($2, NULL); }
155 ;
156
157 twohalves:
158 '(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); }
159 ;
160
161 redirect:
162 IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3;
163 $$.act_port = 0; }
164 | IPSL_REDIRECT '(' ipaddr ',' portnum ')'
165 { $$.act_ip = $3;
166 $$.act_port = $5; }
167 ;
168
169
170 ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
171 { $$ = combine($1,$3,$5,$7); }
172 | YY_STR { $$ = gethostip($1);
173 free($1);
174 }
175 ;
176
177 portnum:
178 YY_NUMBER { $$ = htons($1); }
179 | YY_STR { $$ = getportnum($1);
180 free($1);
181 }
182 ;
183
184 %%
185
186
187 static struct wordtab yywords[] = {
188 { "close", IPSL_CLOSE },
189 { "content", IPSL_CONTENT },
190 { "else", IPSL_ELSE },
191 { "start-group", IPSL_STARTGROUP },
192 { "redirect", IPSL_REDIRECT },
193 { "start", IPSL_START },
194 { "track", IPSL_TRACK },
195 { NULL, 0 }
196 };
197
198
199 int
cram(char * dst,char * src)200 cram(char *dst, char *src)
201 {
202 char c, *s, *t, *u;
203 int i, j, k;
204
205 c = *src;
206 s = src + 1;
207 t = strchr(s, c);
208 *t = '\0';
209 for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) {
210 c = *s++;
211 if (c == '\\') {
212 if (s >= t)
213 break;
214 j = k = 0;
215 do {
216 c = *s++;
217 if (j && (!ISDIGIT(c) || (c > '7') ||
218 (k >= 248))) {
219 *u++ = k, i++;
220 j = k = 0;
221 s--;
222 break;
223 }
224 i++;
225
226 if (ISALPHA(c) || (c > '7')) {
227 switch (c)
228 {
229 case 'n' :
230 *u++ = '\n';
231 break;
232 case 'r' :
233 *u++ = '\r';
234 break;
235 case 't' :
236 *u++ = '\t';
237 break;
238 default :
239 *u++ = c;
240 break;
241 }
242 } else if (ISDIGIT(c)) {
243 j = 1;
244 k <<= 3;
245 k |= (c - '0');
246 i--;
247 } else
248 *u++ = c;
249 } while ((i <= ISC_TLEN) && (s <= t) && (j > 0));
250 } else
251 *u++ = c, i++;
252 }
253 return(i);
254 }
255
256
257 void
printent(ipscan_t * isc)258 printent(ipscan_t *isc)
259 {
260 char buf[ISC_TLEN+1];
261 u_char *u;
262 int i, j;
263
264 buf[ISC_TLEN] = '\0';
265 bcopy(isc->ipsc_ctxt, buf, ISC_TLEN);
266 printf("%s : (\"", isc->ipsc_tag);
267 printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0);
268
269 bcopy(isc->ipsc_cmsk, buf, ISC_TLEN);
270 printf("\", \"%s\"), (\"", buf);
271
272 printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0);
273
274 bcopy(isc->ipsc_smsk, buf, ISC_TLEN);
275 printf("\", \"%s\") = ", buf);
276
277 switch (isc->ipsc_action)
278 {
279 case ISC_A_TRACK :
280 printf("track");
281 break;
282 case ISC_A_REDIRECT :
283 printf("redirect");
284 printf("(%s", inet_ntoa(isc->ipsc_ip));
285 if (isc->ipsc_port)
286 printf(",%d", isc->ipsc_port);
287 printf(")");
288 break;
289 case ISC_A_CLOSE :
290 printf("close");
291 break;
292 default :
293 break;
294 }
295
296 if (isc->ipsc_else != ISC_A_NONE) {
297 printf(" else ");
298 switch (isc->ipsc_else)
299 {
300 case ISC_A_TRACK :
301 printf("track");
302 break;
303 case ISC_A_REDIRECT :
304 printf("redirect");
305 printf("(%s", inet_ntoa(isc->ipsc_eip));
306 if (isc->ipsc_eport)
307 printf(",%d", isc->ipsc_eport);
308 printf(")");
309 break;
310 case ISC_A_CLOSE :
311 printf("close");
312 break;
313 default :
314 break;
315 }
316 }
317 printf("\n");
318
319 if (opts & OPT_DEBUG) {
320 for (u = (u_char *)isc, i = sizeof(*isc); i; ) {
321 printf("#");
322 for (j = 32; (j > 0) && (i > 0); j--, i--)
323 printf("%s%02x", (j & 7) ? "" : " ", *u++);
324 printf("\n");
325 }
326 }
327 if (opts & OPT_VERBOSE) {
328 printf("# hits %d active %d fref %d sref %d\n",
329 isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref,
330 isc->ipsc_sref);
331 }
332 }
333
334
335 void
addtag(char * tstr,char ** cp,char ** sp,struct action * act)336 addtag(char *tstr, char **cp, char **sp, struct action *act)
337 {
338 ipscan_t isc, *iscp;
339
340 bzero((char *)&isc, sizeof(isc));
341
342 strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag));
343 isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0';
344
345 if (cp) {
346 isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]);
347 if (cp[1]) {
348 if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) {
349 fprintf(stderr,
350 "client text/mask strings different length\n");
351 return;
352 }
353 }
354 }
355
356 if (sp) {
357 isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]);
358 if (sp[1]) {
359 if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) {
360 fprintf(stderr,
361 "server text/mask strings different length\n");
362 return;
363 }
364 }
365 }
366
367 if (act->act_val == IPSL_CLOSE) {
368 isc.ipsc_action = ISC_A_CLOSE;
369 } else if (act->act_val == IPSL_TRACK) {
370 isc.ipsc_action = ISC_A_TRACK;
371 } else if (act->act_val == IPSL_REDIRECT) {
372 isc.ipsc_action = ISC_A_REDIRECT;
373 isc.ipsc_ip = act->act_ip;
374 isc.ipsc_port = act->act_port;
375 fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
376 }
377
378 if (act->act_else == IPSL_CLOSE) {
379 isc.ipsc_else = ISC_A_CLOSE;
380 } else if (act->act_else == IPSL_TRACK) {
381 isc.ipsc_else = ISC_A_TRACK;
382 } else if (act->act_else == IPSL_REDIRECT) {
383 isc.ipsc_else = ISC_A_REDIRECT;
384 isc.ipsc_eip = act->act_eip;
385 isc.ipsc_eport = act->act_eport;
386 fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
387 }
388
389 if (!(opts & OPT_DONOTHING)) {
390 iscp = &isc;
391 if (opts & OPT_REMOVE) {
392 if (ioctl(fd, SIOCRMSCA, &iscp) == -1)
393 perror("SIOCADSCA");
394 } else {
395 if (ioctl(fd, SIOCADSCA, &iscp) == -1)
396 perror("SIOCADSCA");
397 }
398 }
399
400 if (opts & OPT_VERBOSE)
401 printent(&isc);
402 }
403
404
405 char **
makepair(char * s1,char * s2)406 makepair(char *s1, char *s2)
407 {
408 char **a;
409
410 a = malloc(sizeof(char *) * 2);
411 a[0] = s1;
412 a[1] = s2;
413 return(a);
414 }
415
416
417 struct in_addr
combine(int a1,int a2,int a3,int a4)418 combine(int a1, int a2, int a3, int a4)
419 {
420 struct in_addr in;
421
422 a1 &= 0xff;
423 in.s_addr = a1 << 24;
424 a2 &= 0xff;
425 in.s_addr |= (a2 << 16);
426 a3 &= 0xff;
427 in.s_addr |= (a3 << 8);
428 a4 &= 0xff;
429 in.s_addr |= a4;
430 in.s_addr = htonl(in.s_addr);
431 return(in);
432 }
433
434
435 struct in_addr
gethostip(char * host)436 gethostip(char *host)
437 {
438 struct hostent *hp;
439 struct in_addr in;
440
441 in.s_addr = 0;
442
443 hp = gethostbyname(host);
444 if (!hp)
445 return(in);
446 bcopy(hp->h_addr, (char *)&in, sizeof(in));
447 return(in);
448 }
449
450
451 int
getportnum(char * port)452 getportnum(char *port)
453 {
454 struct servent *s;
455
456 s = getservbyname(port, "tcp");
457 if (s == NULL)
458 return(-1);
459 return(s->s_port);
460 }
461
462
463 void
showlist(void)464 showlist(void)
465 {
466 ipscanstat_t ipsc, *ipscp = &ipsc;
467 ipscan_t isc;
468
469 if (ioctl(fd, SIOCGSCST, &ipscp) == -1)
470 perror("ioctl(SIOCGSCST)");
471 else if (opts & OPT_SHOWLIST) {
472 while (ipsc.iscs_list != NULL) {
473 if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list,
474 sizeof(isc)) == -1) {
475 perror("kmemcpy");
476 break;
477 } else {
478 printent(&isc);
479 ipsc.iscs_list = isc.ipsc_next;
480 }
481 }
482 } else {
483 printf("scan entries loaded\t%d\n", ipsc.iscs_entries);
484 printf("scan entries matches\t%ld\n", ipsc.iscs_acted);
485 printf("negative matches\t%ld\n", ipsc.iscs_else);
486 }
487 }
488
489
490 void
usage(char * prog)491 usage(char *prog)
492 {
493 fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog);
494 fprintf(stderr, "\t%s [-dlv]\n", prog);
495 exit(1);
496 }
497
498
499 int
main(int argc,char * argv[])500 main(int argc, char *argv[])
501 {
502 FILE *fp = NULL;
503 int c;
504
505 (void) yysettab(yywords);
506
507 if (argc < 2)
508 usage(argv[0]);
509
510 while ((c = getopt(argc, argv, "df:lnrsv")) != -1)
511 switch (c)
512 {
513 case 'd' :
514 opts |= OPT_DEBUG;
515 yydebug++;
516 break;
517 case 'f' :
518 if (!strcmp(optarg, "-"))
519 fp = stdin;
520 else {
521 fp = fopen(optarg, "r");
522 if (!fp) {
523 perror("open");
524 exit(1);
525 }
526 }
527 yyin = fp;
528 break;
529 case 'l' :
530 opts |= OPT_SHOWLIST;
531 break;
532 case 'n' :
533 opts |= OPT_DONOTHING;
534 break;
535 case 'r' :
536 opts |= OPT_REMOVE;
537 break;
538 case 's' :
539 opts |= OPT_STAT;
540 break;
541 case 'v' :
542 opts |= OPT_VERBOSE;
543 break;
544 }
545
546 if (!(opts & OPT_DONOTHING)) {
547 fd = open(IPL_SCAN, O_RDWR);
548 if (fd == -1) {
549 perror("open(IPL_SCAN)");
550 exit(1);
551 }
552 }
553
554 if (fp != NULL) {
555 yylineNum = 1;
556
557 while (!feof(fp))
558 yyparse();
559 fclose(fp);
560 exit(0);
561 }
562
563 if (opts & (OPT_SHOWLIST|OPT_STAT)) {
564 showlist();
565 exit(0);
566 }
567 exit(1);
568 }
569