1 /*
2 * Copyright (c) 2001 Mark Fullmer and The Ohio State University
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: fttag.c,v 1.19 2004/01/05 17:55:37 maf Exp $
27 */
28
29 #include "ftconfig.h"
30 #include "ftlib.h"
31
32 #include "radix.h"
33
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #include <sys/socket.h>
38 #include <sys/resource.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <sys/stat.h>
42 #include <syslog.h>
43 #include <dirent.h>
44 #include <limits.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <time.h>
49 #include <fcntl.h>
50 #include <zlib.h>
51
52 #if HAVE_STRINGS_H
53 #include <strings.h>
54 #endif
55 #if HAVE_STRING_H
56 #include <string.h>
57 #endif
58
59 #if !HAVE_STRSEP
60 char *strsep (char **, const char *);
61 #endif
62
63 extern int max_keylen;
64 extern uint32_t mask_lookup[];
65
66 static struct radix_node_head *rhead;
67
68 struct line_parser {
69 struct fttag_action *cur_action;
70 struct fttag_def *cur_def;
71 struct fttag_def_term *cur_def_term;
72 int state, type;
73 int lineno;
74 char *buf;
75 const char *fname;
76 };
77
78 #define FT_TAG_OR_SRCDST (FT_TAG_OR_SRC_TAG|FT_TAG_OR_DST_TAG)
79 #define FT_TAG_SET_SRCDST (FT_TAG_SET_SRC_TAG|FT_TAG_SET_DST_TAG)
80
81 static int parse_action(struct line_parser *lp, struct fttag *fttag);
82 static int parse_action_type(struct line_parser *lp, struct fttag *fttag);
83 static int parse_action_match(struct line_parser *lp, struct fttag *fttag);
84 static int parse_def(struct line_parser *lp, struct fttag *fttag);
85 static int parse_def_exporter(struct line_parser *lp, struct fttag *fttag);
86 static int parse_def_term(struct line_parser *lp, struct fttag *fttag);
87 static int parse_def_input_filter(struct line_parser *lp, struct fttag *fttag);
88 static int parse_def_output_filter(struct line_parser *lp, struct fttag *fttag);
89 static int parse_def_action(struct line_parser *lp, struct fttag *fttag);
90 static int resolve_actions(struct fttag *fttag);
91
92 static int walk_free(struct radix_node *rn, struct walkarg *UNUSED);
93
94 static void eval_match_src_as(struct fttag_action *fta,
95 struct fts3rec_v1005 *rec);
96 static void eval_match_dst_as(struct fttag_action *fta,
97 struct fts3rec_v1005 *rec);
98 static void eval_match_src_prefix(struct fttag_action *fta,
99 struct fts3rec_v1005 *rec);
100 static void eval_match_dst_prefix(struct fttag_action *fta,
101 struct fts3rec_v1005 *rec);
102 static void eval_match_nexthop(struct fttag_action *fta,
103 struct fts3rec_v1005 *rec);
104 static void eval_match_as(struct fttag_action *fta,
105 struct fts3rec_v1005 *rec);
106 static void eval_match_prefix(struct fttag_action *fta,
107 struct fts3rec_v1005 *rec);
108 static void eval_match_tcp_src_port(struct fttag_action *fta,
109 struct fts3rec_v1005 *rec);
110 static void eval_match_tcp_dst_port(struct fttag_action *fta,
111 struct fts3rec_v1005 *rec);
112 static void eval_match_tcp_port(struct fttag_action *fta,
113 struct fts3rec_v1005 *rec);
114 static void eval_match_udp_src_port(struct fttag_action *fta,
115 struct fts3rec_v1005 *rec);
116 static void eval_match_udp_dst_port(struct fttag_action *fta,
117 struct fts3rec_v1005 *rec);
118 static void eval_match_udp_port(struct fttag_action *fta,
119 struct fts3rec_v1005 *rec);
120 static void eval_match_tos(struct fttag_action *fta,
121 struct fts3rec_v1005 *rec);
122 static void eval_match_any(struct fttag_action *fta,
123 struct fts3rec_v1005 *rec);
124 static void eval_match_in_interface(struct fttag_action *fta,
125 struct fts3rec_v1005 *rec);
126 static void eval_match_out_interface(struct fttag_action *fta,
127 struct fts3rec_v1005 *rec);
128 static void eval_match_interface(struct fttag_action *fta,
129 struct fts3rec_v1005 *rec);
130 static void eval_match_exporter(struct fttag_action *fta,
131 struct fts3rec_v1005 *rec);
132 static void eval_match_src_ip(struct fttag_action *fta,
133 struct fts3rec_v1005 *rec);
134 static void eval_match_dst_ip(struct fttag_action *fta,
135 struct fts3rec_v1005 *rec);
136 static void eval_match_ip(struct fttag_action *fta,
137 struct fts3rec_v1005 *rec);
138
139 #define PARSE_STATE_ACTION 0x1
140 #define PARSE_STATE_DEFINITION 0x2
141
142 #define NEXT_WORD(A,B)\
143 for (;;) {\
144 B = strsep(A, " \t");\
145 if ((B && *B != 0) || (!B))\
146 break;\
147 }\
148
149 struct jump {
150 char *name;
151 int state;
152 int (*func)(struct line_parser *lp, struct fttag *fttag);
153 };
154
155 static struct jump pjump[] = {{"tag-action", 0, parse_action},
156 {"type", PARSE_STATE_ACTION, parse_action_type},
157 {"match", PARSE_STATE_ACTION, parse_action_match},
158 {"tag-definition", 0, parse_def},
159 {"exporter", PARSE_STATE_DEFINITION, parse_def_exporter},
160 {"term", PARSE_STATE_DEFINITION, parse_def_term},
161 {"input-filter", PARSE_STATE_DEFINITION, parse_def_input_filter},
162 {"output-filter", PARSE_STATE_DEFINITION, parse_def_output_filter},
163 {"action", PARSE_STATE_DEFINITION, parse_def_action},
164 {0, 0, 0},
165 };
166 /*
167 * data structures:
168 *
169 *
170 * fttag holds the head pointers to a list of actions, and definitions.
171 *
172 * Each definition holds a list of terms. A term is a combination of
173 * an input filter, output filter and list of actions.
174 *
175 * struct fttag_def : linked list of definitions
176 * struct fttag_action : linked list of actions
177 * struct fttag_def_term : each term in a definition
178 * struct fttag_def_term_actions : each action in a term
179 *
180 * actions contain one of the following:
181 *
182 * struct fttag_prefix_look : prefix radix trie lookup entry
183 * struct fttag_as_look : AS table lookup
184 * struct fttag_port_look : port table lookup
185 * struct fttag_tos_look : tos table lookup
186 * struct fttag_next_hop_look : next hop hash lookup entry
187 * struct fttag_interface_look : interface table lookup entry
188 * struct fttag_exporter : exporter hash lookup entry
189 * struct fttag_ip_look : IP address hash lookup entry
190 *
191 * struct fftag_exp_hash : hash table mapping exporter_ip
192 * to list of definitions. Used
193 * when processing flows. ie, lookup
194 * by exporter, test input/output
195 * filter then use action to add
196 * tags.
197 *
198 */
199
200 struct fttag_prefix_look {
201 struct radix_node rt_nodes[2]; /* radix tree glue */
202 struct radix_sockaddr_in addr;
203 uint8_t masklen;
204 uint16_t set_flags;
205 uint32_t src_tag;
206 uint32_t dst_tag;
207 };
208
209 struct fttag_as_look {
210 uint16_t set_flags_lookup[65536];
211 uint32_t src_tag_lookup[65536];
212 uint32_t dst_tag_lookup[65536];
213 };
214
215 struct fttag_port_look {
216 uint16_t set_flags_lookup[65536];
217 uint32_t src_tag_lookup[65536];
218 uint32_t dst_tag_lookup[65536];
219 };
220
221 struct fttag_tos_look {
222 uint16_t set_flags_lookup[256];
223 uint32_t src_tag_lookup[256];
224 uint32_t dst_tag_lookup[256];
225 };
226
227 struct fttag_interface_look {
228 uint16_t set_flags_lookup[65536];
229 uint32_t src_tag_lookup[65536];
230 uint32_t dst_tag_lookup[65536];
231 };
232
233 struct fttag_any_look {
234 uint16_t set_flags;
235 uint32_t src_tag;
236 uint32_t dst_tag;
237 };
238
239 struct fttag_next_hop_look {
240 FT_SLIST_ENTRY(fttag_next_hop_look) chain;
241 uint32_t addr; /* key */
242 uint16_t set_flags;
243 uint32_t src_tag;
244 uint32_t dst_tag;
245 };
246
247 struct fttag_exporter_look {
248 FT_SLIST_ENTRY(fttag_exporter_look) chain;
249 uint32_t addr; /* key */
250 uint16_t set_flags;
251 uint32_t src_tag;
252 uint32_t dst_tag;
253 };
254
255 struct fttag_ip_look {
256 FT_SLIST_ENTRY(fttag_ip_look) chain;
257 uint32_t addr; /* key */
258 uint16_t set_flags;
259 uint32_t src_tag;
260 uint32_t dst_tag;
261 };
262
263 /*
264 * function: fttag_load
265 *
266 * Process fname into fttag.
267 *
268 * returns: 0 ok
269 * <0 fail
270 */
fttag_load(struct fttag * fttag,struct ftvar * ftvar,const char * fname)271 int fttag_load(struct fttag *fttag, struct ftvar *ftvar, const char *fname)
272 {
273 static int rn_init_called;
274 struct stat sb;
275 struct jump *jmp;
276 struct line_parser lp;
277 int fd, ret, found = 0;
278 char *buf, *buf2, *c;
279 char sbuf[FT_LP_MAXLINE];
280
281 ret = -1;
282 buf = (char*)0L;
283 bzero(&lp, sizeof lp);
284 bzero(fttag, sizeof *fttag);
285
286 if (!rn_init_called) {
287 max_keylen = sizeof(struct radix_sockaddr_in);
288 rn_init();
289 rn_init_called = 1;
290 }
291
292 FT_SLIST_INIT(&fttag->defs);
293 FT_SLIST_INIT(&fttag->actions);
294
295 lp.fname = fname;
296
297 if ((fd = open(fname, O_RDONLY, 0)) < 0) {
298 fterr_warn("open(%s)", fname);
299 goto load_tags_out;
300 }
301
302 if (fstat(fd, &sb) < 0) {
303 fterr_warn("stat(%s)", fname);
304 goto load_tags_out;
305 }
306
307 /* allocate storage for file */
308 if (!(buf = malloc(sb.st_size+1))) {
309 fterr_warn("malloc()");
310 goto load_tags_out;
311 }
312
313 /* read in file */
314 if (read(fd, buf, sb.st_size) != sb.st_size) {
315 fterr_warnx("read(%s): short", fname);
316 goto load_tags_out;
317 }
318
319 /* null terminate file */
320 buf[sb.st_size] = 0;
321
322 buf2 = buf;
323
324 for (;;) {
325
326 /* rip a line */
327 for (;;) {
328 c = strsep(&buf2, "\n");
329 ++lp.lineno;
330 if ((c && *c != 0) || (!c))
331 break;
332 }
333
334 /* no more lines */
335 if (!c) {
336 goto load_tags_done;
337 }
338
339 /* do variable substitutions first */
340 if (ftvar) {
341 if (ftvar_evalstr(ftvar, c, sbuf, sizeof(sbuf)) < 0) {
342 fterr_warnx("ftvar_evalstr(): failed");
343 goto load_tags_done;
344 }
345 } else {
346 strncpy(sbuf, c, sizeof(sbuf));
347 sbuf[sizeof(sbuf)-1] = 0;
348 }
349
350 lp.buf = sbuf;
351
352 /* first word */
353 NEXT_WORD(&lp.buf, c);
354
355 /* whitespace only line */
356 if (!c) {
357 continue;
358 }
359
360 /* comment line */
361 if (c && *c == '#')
362 continue;
363
364 for (jmp = pjump; jmp->name; ++jmp) {
365
366 found = 0;
367
368 if (((!jmp->state) || (jmp->state & lp.state))
369 && (!strcasecmp(c, jmp->name))) {
370
371 found = 1;
372
373 if (jmp->func(&lp, fttag))
374 goto load_tags_out;
375
376 NEXT_WORD(&lp.buf, c);
377
378 if (c) {
379 fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c);
380 goto load_tags_out;
381 }
382
383 break;
384
385 }
386
387 } /* test each word */
388
389 if (!found) {
390 fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c);
391 goto load_tags_out;
392 }
393
394 } /* more lines */
395
396 load_tags_done:
397
398 if (resolve_actions(fttag))
399 goto load_tags_out;
400
401 ret = 0;
402
403 load_tags_out:
404
405 if (fd != -1)
406 close(fd);
407
408 if (buf)
409 free(buf);
410
411 if (ret == -1)
412 fttag_free(fttag);
413
414 return ret;
415
416 } /* fttag_load */
417
418 /*
419 * function: fttag_defintion_find
420 *
421 * Return a pointer to a fttag_def_lookup for use later with
422 * fttag_def_eval
423 *
424 * Note this allocates storage and precomputes a hash table
425 * to speed up the eval phase. Storage is freed by fttag_free()
426 *
427 * returns : pointer to fttag_def_lookup or null if not found or error.
428 *
429 */
fttag_def_find(struct fttag * fttag,const char * name)430 struct fttag_def *fttag_def_find(struct fttag *fttag, const char *name)
431 {
432 struct fttag_def *ftd;
433
434 /* foreach definition */
435 FT_SLIST_FOREACH(ftd, &fttag->defs, chain) {
436
437 if (!(strcasecmp(ftd->name, name)))
438 return ftd;
439
440 }
441
442 return (struct fttag_def*)0L;
443
444 } /* fttag_def_find */
445
446 /*
447 * function: parse_action
448 *
449 * process the 'action' line. Each action has a unique name which
450 * is added to the fttag->actions linked list. The current action is
451 * updated in lp. Actions by themself do nothing, they must be pointed
452 * to by a definition.
453 *
454 * returns: 0 ok
455 * <0 fail
456 */
parse_action(struct line_parser * lp,struct fttag * fttag)457 int parse_action(struct line_parser *lp, struct fttag *fttag)
458 {
459 char *c;
460 struct fttag_action *fta;
461
462 NEXT_WORD(&lp->buf, c);
463
464 if (!c) {
465 fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno);
466 return -1;
467 }
468
469 /* check if it exists */
470 FT_SLIST_FOREACH(fta, &fttag->actions, chain) {
471
472 if (!strcasecmp(c, fta->name)) {
473 fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname,
474 lp->lineno, c);
475 return -1;
476 }
477
478 }
479
480 /* no, add a new entry to the list */
481 if (!(fta = (struct fttag_action*)malloc(sizeof (struct fttag_action)))) {
482 fterr_warn("malloc()");
483 return -1;
484 }
485
486 bzero(fta, sizeof *fta);
487
488 if (!(fta->name = (char*)malloc(strlen(c)+1))) {
489 fterr_warn("malloc()");
490 free(fta);
491 return -1;
492 }
493
494 strcpy(fta->name, c);
495
496 FT_SLIST_INSERT_HEAD(&fttag->actions, fta, chain);
497
498 lp->state = PARSE_STATE_ACTION;
499 lp->cur_action = fta;
500
501 return 0;
502
503 } /* parse_action */
504
505 /*
506 * function: parse_action_type
507 *
508 * process the 'type' line. When the type is set the initial storage
509 * (table/hash/radix trie) is allocated.
510 *
511 * returns: 0 ok
512 * <0 fail
513 */
parse_action_type(struct line_parser * lp,struct fttag * fttag)514 int parse_action_type(struct line_parser *lp, struct fttag *fttag)
515 {
516 char *c;
517
518 if (!lp->cur_action) {
519 fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno);
520 return -1;
521 }
522
523 NEXT_WORD(&lp->buf, c);
524
525 if (!c) {
526 fterr_warnx("%s line %d: Expecting type.", lp->fname, lp->lineno);
527 return -1;
528 }
529
530 if (lp->cur_action->type) {
531 fterr_warnx("%s line %d: Type previously defined.", lp->fname, lp->lineno);
532 return -1;
533 }
534
535 if (!strcasecmp(c, "src-prefix")) {
536 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_PREFIX;
537 lp->cur_action->eval = eval_match_src_prefix;
538 } else if (!strcasecmp(c, "source-prefix")) {
539 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_PREFIX;
540 lp->cur_action->eval = eval_match_src_prefix;
541 } else if (!strcasecmp(c, "dst-prefix")) {
542 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_PREFIX;
543 lp->cur_action->eval = eval_match_dst_prefix;
544 } else if (!strcasecmp(c, "destination-prefix")) {
545 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_PREFIX;
546 lp->cur_action->eval = eval_match_dst_prefix;
547 } else if (!strcasecmp(c, "prefix")) {
548 lp->cur_action->eval = eval_match_prefix;
549 lp->cur_action->type = FT_TAG_TYPE_MATCH_PREFIX;
550 } else if (!strcasecmp(c, "next-hop")) {
551 lp->cur_action->eval = eval_match_nexthop;
552 lp->cur_action->type = FT_TAG_TYPE_MATCH_NEXTHOP;
553 } else if (!strcasecmp(c, "src-as")) {
554 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_AS;
555 lp->cur_action->eval = eval_match_src_as;
556 } else if (!strcasecmp(c, "source-as")) {
557 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_AS;
558 lp->cur_action->eval = eval_match_src_as;
559 } else if (!strcasecmp(c, "dst-as")) {
560 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_AS;
561 lp->cur_action->eval = eval_match_dst_as;
562 } else if (!strcasecmp(c, "destination-as")) {
563 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_AS;
564 lp->cur_action->eval = eval_match_dst_as;
565 } else if (!strcasecmp(c, "as")) {
566 lp->cur_action->eval = eval_match_as;
567 lp->cur_action->type = FT_TAG_TYPE_MATCH_AS;
568 } else if (!strcasecmp(c, "tcp-src-port")) {
569 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_TCP_PORT;
570 lp->cur_action->eval = eval_match_tcp_src_port;
571 } else if (!strcasecmp(c, "tcp-source-port")) {
572 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_TCP_PORT;
573 lp->cur_action->eval = eval_match_tcp_src_port;
574 } else if (!strcasecmp(c, "tcp-dst-port")) {
575 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_TCP_PORT;
576 lp->cur_action->eval = eval_match_tcp_dst_port;
577 } else if (!strcasecmp(c, "tcp-destination-port")) {
578 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_TCP_PORT;
579 lp->cur_action->eval = eval_match_tcp_dst_port;
580 } else if (!strcasecmp(c, "tcp-port")) {
581 lp->cur_action->eval = eval_match_tcp_port;
582 lp->cur_action->type = FT_TAG_TYPE_MATCH_TCP_PORT;
583 } else if (!strcasecmp(c, "udp-src-port")) {
584 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_UDP_PORT;
585 lp->cur_action->eval = eval_match_udp_src_port;
586 } else if (!strcasecmp(c, "udp-source-port")) {
587 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_UDP_PORT;
588 lp->cur_action->eval = eval_match_udp_src_port;
589 } else if (!strcasecmp(c, "udp-dst-port")) {
590 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_UDP_PORT;
591 lp->cur_action->eval = eval_match_udp_dst_port;
592 } else if (!strcasecmp(c, "udp-destination-port")) {
593 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_UDP_PORT;
594 lp->cur_action->eval = eval_match_udp_dst_port;
595 } else if (!strcasecmp(c, "udp-port")) {
596 lp->cur_action->eval = eval_match_udp_port;
597 lp->cur_action->type = FT_TAG_TYPE_MATCH_TCP_PORT;
598 } else if (!strcasecmp(c, "tos")) {
599 lp->cur_action->eval = eval_match_tos;
600 lp->cur_action->type = FT_TAG_TYPE_MATCH_TOS;
601 } else if (!strcasecmp(c, "any")) {
602 lp->cur_action->eval = eval_match_any;
603 lp->cur_action->type = FT_TAG_TYPE_MATCH_ANY;
604 } else if (!strcasecmp(c, "src-ip")) {
605 lp->cur_action->eval = eval_match_src_ip;
606 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_IP;
607 } else if (!strcasecmp(c, "source-ip-address")) {
608 lp->cur_action->eval = eval_match_src_ip;
609 lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_IP;
610 } else if (!strcasecmp(c, "dst-ip")) {
611 lp->cur_action->eval = eval_match_dst_ip;
612 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_IP;
613 } else if (!strcasecmp(c, "destination-ip-address")) {
614 lp->cur_action->eval = eval_match_dst_ip;
615 lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_IP;
616 } else if (!strcasecmp(c, "ip")) {
617 lp->cur_action->eval = eval_match_ip;
618 lp->cur_action->type = FT_TAG_TYPE_MATCH_IP;
619 } else if (!strcasecmp(c, "exporter")) {
620 lp->cur_action->eval = eval_match_exporter;
621 lp->cur_action->type = FT_TAG_TYPE_MATCH_EXPORTER;
622 } else if (!strcasecmp(c, "input-interface")) {
623 lp->cur_action->eval = eval_match_in_interface;
624 lp->cur_action->type = FT_TAG_TYPE_MATCH_IN_INTERFACE;
625 } else if (!strcasecmp(c, "output-interface")) {
626 lp->cur_action->eval = eval_match_out_interface;
627 lp->cur_action->type = FT_TAG_TYPE_MATCH_OUT_INTERFACE;
628 } else if (!strcasecmp(c, "interface")) {
629 lp->cur_action->eval = eval_match_interface;
630 lp->cur_action->type = FT_TAG_TYPE_MATCH_INTERFACE;
631 } else {
632 fterr_warnx("%s line %d: Unrecognized type.", lp->fname, lp->lineno);
633 return -1;
634 }
635
636 /* allocate storage for lookup */
637
638 if ((lp->cur_action->type & FT_TAG_TYPE_MATCH_AS)) {
639
640 if (!(lp->cur_action->look = malloc(sizeof (struct fttag_as_look)))) {
641 fterr_warn("malloc()");
642 return -1;
643 }
644
645 bzero(lp->cur_action->look, sizeof (struct fttag_as_look));
646
647 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_TOS) {
648
649 if (!(lp->cur_action->look = malloc(sizeof (struct fttag_tos_look)))) {
650 fterr_warn("malloc()");
651 return -1;
652 }
653
654 bzero(lp->cur_action->look, sizeof (struct fttag_tos_look));
655
656 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_ANY) {
657
658 if (!(lp->cur_action->look = malloc(sizeof (struct fttag_any_look)))) {
659 fterr_warn("malloc()");
660 return -1;
661 }
662
663 bzero(lp->cur_action->look, sizeof (struct fttag_any_look));
664
665 } else if (lp->cur_action->type &
666 (FT_TAG_TYPE_MATCH_TCP_PORT|FT_TAG_TYPE_MATCH_UDP_PORT)) {
667
668 if (!(lp->cur_action->look = malloc(sizeof (struct fttag_port_look)))) {
669 fterr_warn("malloc()");
670 return -1;
671 }
672
673 bzero(lp->cur_action->look, sizeof (struct fttag_port_look));
674
675 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_PREFIX) {
676
677 if (rn_inithead((void**)&lp->cur_action->look, 32) < 0) {
678 fterr_warnx("rn_inithead(): failed");
679 return -1;
680 }
681
682 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_NEXTHOP) {
683
684 if (!(lp->cur_action->look = ftchash_new(256, sizeof
685 (struct fttag_next_hop_look), 4, 16))) {
686 fterr_warnx("ftchash_new(): failed");
687 return -1;
688 }
689
690 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_EXPORTER) {
691
692 if (!(lp->cur_action->look = ftchash_new(256, sizeof
693 (struct fttag_exporter_look), 4, 16))) {
694 fterr_warnx("ftchash_new(): failed");
695 return -1;
696 }
697
698 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_IP) {
699
700 if (!(lp->cur_action->look = ftchash_new(256, sizeof
701 (struct fttag_ip_look), 4, 16))) {
702 fterr_warnx("ftchash_new(): failed");
703 return -1;
704 }
705
706 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_INTERFACE) {
707
708 if (!(lp->cur_action->look = malloc(sizeof (struct fttag_interface_look)))) {
709 fterr_warn("malloc()");
710 return -1;
711 }
712
713 bzero(lp->cur_action->look, sizeof (struct fttag_interface_look));
714 }
715
716 return 0;
717
718 } /* parse_action_type */
719
720 /*
721 * function: parse_action_match
722 *
723 * process the 'match/set' line. The match action depends on the type which
724 * must be configured first. An AS match is added to a table, a next-hop
725 * is added to a hash (chash_*) and a prefix is added to a radix trie, etc.
726 *
727 * returns: 0 ok
728 * <0 fail
729 */
parse_action_match(struct line_parser * lp,struct fttag * fttag)730 int parse_action_match(struct line_parser *lp, struct fttag *fttag)
731 {
732 struct radix_sockaddr_in sock1, sock2;
733 struct fttag_as_look *as_look;
734 struct fttag_next_hop_look *nh_look, nh_look2;
735 struct fttag_prefix_look *prefix_look;
736 struct fttag_port_look *port_look;
737 struct fttag_tos_look *tos_look;
738 struct fttag_interface_look *interface_look;
739 struct fttag_exporter_look *exporter_look, exporter_look2;
740 struct fttag_ip_look *ip_look, ip_look2;
741 struct fttag_any_look *any_look;
742 struct ip_prefix ipp;
743 struct radix_node_head *rhead;
744 uint32_t tag, hash, ipaddr;
745 uint16_t as, port, interface;
746 uint8_t tos;
747 int sflag, new, tflag2, tmpflag, tflag;
748 char *c, *match;
749
750 if (!lp->cur_action->type) {
751 fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno);
752 return -1;
753 }
754
755 bzero(&sock1, sizeof sock1);
756 bzero(&sock2, sizeof sock2);
757
758 sock1.sin_family = AF_INET;
759 sock1.sin_len = sizeof (struct radix_sockaddr_in);
760
761 sock2.sin_family = AF_INET;
762 sock2.sin_len = sizeof (struct radix_sockaddr_in);
763
764 as_look = lp->cur_action->look;
765 nh_look = lp->cur_action->look;
766 prefix_look = lp->cur_action->look;
767 port_look = lp->cur_action->look;
768 tos_look = lp->cur_action->look;
769 any_look = lp->cur_action->look;
770 interface_look = lp->cur_action->look;
771 ip_look = lp->cur_action->look;
772 exporter_look = lp->cur_action->look;
773
774 NEXT_WORD(&lp->buf, c);
775
776 if (!c) {
777 fterr_warnx("%s line %d: Expecting match data.", lp->fname, lp->lineno);
778 return -1;
779 }
780
781 match = c;
782
783 NEXT_WORD(&lp->buf, c);
784
785 if (!c) {
786 fterr_warnx("%s line %d: Expecting [set|or]-[source|destination].",
787 lp->fname, lp->lineno);
788 return -1;
789 }
790
791 if (!strcasecmp(c, "set-src")) {
792 sflag = FT_TAG_SET_SRC_TAG;
793 tflag = FT_TAG_SET_SRC_TAG;
794 tflag2 = FT_TAG_OR_SRC_TAG;
795 } else if (!strcasecmp(c, "set-source")) {
796 sflag = FT_TAG_SET_SRC_TAG;
797 tflag = FT_TAG_SET_SRC_TAG;
798 tflag2 = FT_TAG_OR_SRC_TAG;
799 } else if (!strcasecmp(c, "set-dst")) {
800 sflag = FT_TAG_SET_DST_TAG;
801 tflag = FT_TAG_SET_DST_TAG;
802 tflag2 = FT_TAG_OR_DST_TAG;
803 } else if (!strcasecmp(c, "set-destination")) {
804 sflag = FT_TAG_SET_DST_TAG;
805 tflag = FT_TAG_SET_DST_TAG;
806 tflag2 = FT_TAG_OR_DST_TAG;
807 } else if (!strcasecmp(c, "or-src")) {
808 sflag = FT_TAG_OR_SRC_TAG;
809 tflag = FT_TAG_SET_SRC_TAG;
810 tflag2 = 0;
811 } else if (!strcasecmp(c, "or-source")) {
812 sflag = FT_TAG_OR_SRC_TAG;
813 tflag = FT_TAG_SET_SRC_TAG;
814 tflag2 = 0;
815 } else if (!strcasecmp(c, "or-dst")) {
816 sflag = FT_TAG_OR_DST_TAG;
817 tflag = FT_TAG_SET_DST_TAG;
818 tflag2 = 0;
819 } else if (!strcasecmp(c, "or-destination")) {
820 sflag = FT_TAG_OR_DST_TAG;
821 tflag = FT_TAG_SET_DST_TAG;
822 tflag2 = 0;
823 } else {
824 fterr_warnx("%s line %d: Expecting [set|or]-[source|destination].",
825 lp->fname, lp->lineno);
826 return -1;
827 }
828
829
830 /*
831 * The data structure allows one SET or multiple OR's per
832 * source/destination tag. Enforce this in the config parser
833 *
834 * Error conditions
835 * current sflag
836 * ------------------------
837 * SET_SRC and SET_SRC
838 * SET_DST and SET_DST
839 * or
840 * SET_SRC and OR_SRC
841 * SET_DST and OR_DST
842 * or
843 * OR_SRC and SET_SRC
844 * OR_DST and SET_DST
845 */
846
847 NEXT_WORD(&lp->buf, c);
848
849 if (!c) {
850 fterr_warnx("%s line %d: Expecting set data.", lp->fname, lp->lineno);
851 return -1;
852 }
853
854 tag = strtoul(c, (char **)0L, 0);
855
856 if (lp->cur_action->type & FT_TAG_TYPE_MATCH_AS) {
857
858 as = atoi(match);
859
860 tmpflag = as_look->set_flags_lookup[as];
861
862 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
863 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
864 fterr_warnx(
865 "%s line %d: Only one set per source/destination per match.",
866 lp->fname, lp->lineno);
867 return -1;
868 }
869
870 as_look->set_flags_lookup[as] |= sflag;
871
872 if (sflag & FT_TAG_SET_SRC_TAG)
873 as_look->src_tag_lookup[as] = tag;
874
875 if (sflag & FT_TAG_OR_SRC_TAG)
876 as_look->src_tag_lookup[as] |= tag;
877
878 if (sflag & FT_TAG_SET_DST_TAG)
879 as_look->dst_tag_lookup[as] = tag;
880
881 if (sflag & FT_TAG_OR_DST_TAG)
882 as_look->dst_tag_lookup[as] |= tag;
883
884 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_INTERFACE) {
885
886 interface = atoi(match);
887
888 tmpflag = interface_look->set_flags_lookup[interface];
889
890 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
891 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
892 fterr_warnx(
893 "%s line %d: Only one set per source/destination per match.",
894 lp->fname, lp->lineno);
895 return -1;
896 }
897
898 interface_look->set_flags_lookup[interface] |= sflag;
899
900 if (sflag & FT_TAG_SET_SRC_TAG)
901 interface_look->src_tag_lookup[interface] = tag;
902
903 if (sflag & FT_TAG_OR_SRC_TAG)
904 interface_look->src_tag_lookup[interface] |= tag;
905
906 if (sflag & FT_TAG_SET_DST_TAG)
907 interface_look->dst_tag_lookup[interface] = tag;
908
909 if (sflag & FT_TAG_OR_DST_TAG)
910 interface_look->dst_tag_lookup[interface] |= tag;
911
912
913 } else if (lp->cur_action->type &
914 (FT_TAG_TYPE_MATCH_TCP_PORT|FT_TAG_TYPE_MATCH_UDP_PORT)) {
915
916 port = atoi(match);
917
918 tmpflag = port_look->set_flags_lookup[port];
919
920 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
921 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
922 fterr_warnx(
923 "%s line %d: Only one set per source/destination per match.",
924 lp->fname, lp->lineno);
925 return -1;
926 }
927
928 port_look->set_flags_lookup[port] |= sflag;
929
930 if (sflag & FT_TAG_SET_SRC_TAG)
931 port_look->src_tag_lookup[port] = tag;
932
933 if (sflag & FT_TAG_OR_SRC_TAG)
934 port_look->src_tag_lookup[port] |= tag;
935
936 if (sflag & FT_TAG_SET_DST_TAG)
937 port_look->dst_tag_lookup[port] = tag;
938
939 if (sflag & FT_TAG_OR_DST_TAG)
940 port_look->dst_tag_lookup[port] |= tag;
941
942 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_TOS) {
943
944 tos = atoi(match);
945
946 tmpflag = tos_look->set_flags_lookup[tos];
947
948 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
949 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
950 fterr_warnx(
951 "%s line %d: Only one set per source/destination per match.",
952 lp->fname, lp->lineno);
953 return -1;
954 }
955
956 tos_look->set_flags_lookup[tos] |= sflag;
957
958 if (sflag & FT_TAG_SET_SRC_TAG)
959 tos_look->src_tag_lookup[tos] = tag;
960
961 if (sflag & FT_TAG_OR_SRC_TAG)
962 tos_look->src_tag_lookup[tos] |= tag;
963
964 if (sflag & FT_TAG_SET_DST_TAG)
965 tos_look->dst_tag_lookup[tos] = tag;
966
967 if (sflag & FT_TAG_OR_DST_TAG)
968 tos_look->dst_tag_lookup[tos] |= tag;
969
970 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_ANY) {
971
972 if (strcasecmp(match, "any")) {
973 fterr_warnx("%s line %d: Match must be any.", lp->fname, lp->lineno);
974 return -1;
975 }
976
977 tmpflag = any_look->set_flags;
978
979 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
980 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
981 fterr_warnx(
982 "%s line %d: Only one set per source/destination per match.",
983 lp->fname, lp->lineno);
984 return -1;
985 }
986
987 any_look->set_flags |= sflag;
988
989 if (sflag & FT_TAG_SET_SRC_TAG)
990 any_look->src_tag = tag;
991
992 if (sflag & FT_TAG_OR_SRC_TAG)
993 any_look->src_tag |= tag;
994
995 if (sflag & FT_TAG_SET_DST_TAG)
996 any_look->dst_tag = tag;
997
998 if (sflag & FT_TAG_OR_DST_TAG)
999 any_look->dst_tag |= tag;
1000
1001 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_PREFIX) {
1002
1003 ipp = scan_ip_prefix(match);
1004 sock1.sin_addr.s_addr = ipp.addr;
1005 sock2.sin_addr.s_addr = (!ipp.len) ? 0 : mask_lookup[ipp.len];
1006
1007 rhead = lp->cur_action->look;
1008
1009 /* try to retrieve from trie */
1010 prefix_look = (struct fttag_prefix_look*)rhead->rnh_lookup(&sock1,
1011 &sock2, rhead);
1012
1013 new = 1;
1014
1015 /* if it exists, make sure not a duplicate set */
1016 if (prefix_look && (prefix_look->addr.sin_addr.s_addr == ipp.addr) &&
1017 (prefix_look->masklen == ipp.len)) {
1018
1019 tmpflag = prefix_look->set_flags;
1020
1021 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1022 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1023 fterr_warnx(
1024 "%s line %d: Only one set per source/destination per match.",
1025 lp->fname, lp->lineno);
1026 return -1;
1027 } else {
1028 new = 0;
1029 }
1030
1031 }
1032
1033 /* allocate a new prefix lookup */
1034 if (new) {
1035
1036 if (!(prefix_look = (struct fttag_prefix_look*)malloc(sizeof
1037 (struct fttag_prefix_look)))) {
1038 fterr_warn("malloc(prefix_look)");
1039 return -1;
1040 }
1041
1042 bzero(prefix_look, sizeof *prefix_look);
1043
1044 prefix_look->rt_nodes->rn_key = (caddr_t)&prefix_look->addr;
1045
1046 prefix_look->addr.sin_addr.s_addr = ipp.addr;
1047 prefix_look->addr.sin_len = sizeof (struct radix_sockaddr_in);
1048 prefix_look->addr.sin_family = AF_INET;
1049
1050 sock1.sin_addr.s_addr = (!ipp.len) ? 0 : mask_lookup[ipp.len];
1051
1052 prefix_look->masklen = ipp.len;
1053
1054 /* add it to the trie */
1055 if (!rhead->rnh_addaddr(&prefix_look->addr, &sock1, rhead,
1056 prefix_look->rt_nodes)) {
1057 free(prefix_look);
1058 fterr_warnx("rnh_addaddr(): failed for %s",match);
1059 return -1;
1060 }
1061
1062 } /* new */
1063
1064 /* finish filling in */
1065
1066 prefix_look->set_flags |= sflag;
1067
1068 if (sflag & FT_TAG_SET_SRC_TAG)
1069 prefix_look->src_tag = tag;
1070
1071 if (sflag & FT_TAG_OR_SRC_TAG)
1072 prefix_look->src_tag |= tag;
1073
1074 if (sflag & FT_TAG_SET_DST_TAG)
1075 prefix_look->dst_tag = tag;
1076
1077 if (sflag & FT_TAG_OR_DST_TAG)
1078 prefix_look->dst_tag |= tag;
1079
1080
1081 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_NEXTHOP) {
1082
1083 ipaddr = scan_ip(match);
1084
1085 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1086 hash = (hash>>8) ^ (hash & 0xFF);
1087
1088 nh_look = ftchash_lookup(lp->cur_action->look, &ipaddr, hash);
1089
1090 new = 1;
1091
1092 /* if it exists, make sure not a duplicate set */
1093 if (nh_look) {
1094
1095 tmpflag = nh_look->set_flags;
1096
1097 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1098 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1099 fterr_warnx(
1100 "%s line %d: Only one set per source/destination per match.",
1101 lp->fname, lp->lineno);
1102 return -1;
1103 } else {
1104 new = 0;
1105 }
1106
1107 }
1108
1109 if (new) {
1110
1111 bzero(&nh_look2, sizeof nh_look2);
1112
1113 nh_look2.addr = ipaddr;
1114
1115 if (!(nh_look = ftchash_update(lp->cur_action->look, &nh_look2, hash))) {
1116 fterr_warnx("ftch_update(): failed");
1117 return -1;
1118 }
1119
1120 }
1121
1122 /* finish filling in fields */
1123
1124 nh_look->set_flags |= sflag;
1125
1126 if (sflag & FT_TAG_SET_SRC_TAG)
1127 nh_look->src_tag = tag;
1128
1129 if (sflag & FT_TAG_OR_SRC_TAG)
1130 nh_look->src_tag |= tag;
1131
1132 if (sflag & FT_TAG_SET_DST_TAG)
1133 nh_look->dst_tag = tag;
1134
1135 if (sflag & FT_TAG_OR_DST_TAG)
1136 nh_look->dst_tag |= tag;
1137
1138 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_EXPORTER) {
1139
1140 ipaddr = scan_ip(match);
1141
1142 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1143 hash = (hash>>8) ^ (hash & 0xFF);
1144
1145 exporter_look = ftchash_lookup(lp->cur_action->look, &ipaddr, hash);
1146
1147 new = 1;
1148
1149 /* if it exists, make sure not a duplicate set */
1150 if (exporter_look) {
1151
1152 tmpflag = exporter_look->set_flags;
1153
1154 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1155 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1156 fterr_warnx(
1157 "%s line %d: Only one set per source/destination per match.",
1158 lp->fname, lp->lineno);
1159 return -1;
1160 } else {
1161 new = 0;
1162 }
1163
1164 }
1165
1166 if (new) {
1167
1168 bzero(&exporter_look2, sizeof exporter_look2);
1169
1170 exporter_look2.addr = ipaddr;
1171
1172 if (!(exporter_look = ftchash_update(lp->cur_action->look,
1173 &exporter_look2, hash))) {
1174 fterr_warnx("ftch_update(): failed");
1175 return -1;
1176 }
1177
1178 }
1179
1180 /* finish filling in fields */
1181
1182 exporter_look->set_flags |= sflag;
1183
1184 if (sflag & FT_TAG_SET_SRC_TAG)
1185 exporter_look->src_tag = tag;
1186
1187 if (sflag & FT_TAG_OR_SRC_TAG)
1188 exporter_look->src_tag |= tag;
1189
1190 if (sflag & FT_TAG_SET_DST_TAG)
1191 exporter_look->dst_tag = tag;
1192
1193 if (sflag & FT_TAG_OR_DST_TAG)
1194 exporter_look->dst_tag |= tag;
1195
1196 } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_IP) {
1197
1198 ipaddr = scan_ip(match);
1199
1200 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1201 hash = (hash>>8) ^ (hash & 0xFF);
1202
1203 ip_look = ftchash_lookup(lp->cur_action->look, &ipaddr, hash);
1204
1205 new = 1;
1206
1207 /* if it exists, make sure not a duplicate set */
1208 if (ip_look) {
1209
1210 tmpflag = ip_look->set_flags;
1211
1212 if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1213 ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1214 fterr_warnx(
1215 "%s line %d: Only one set per source/destination per match.",
1216 lp->fname, lp->lineno);
1217 return -1;
1218 } else {
1219 new = 0;
1220 }
1221
1222 }
1223
1224 if (new) {
1225
1226 bzero(&ip_look2, sizeof ip_look2);
1227
1228 ip_look2.addr = ipaddr;
1229
1230 if (!(ip_look = ftchash_update(lp->cur_action->look,
1231 &ip_look2, hash))) {
1232 fterr_warnx("ftch_update(): failed");
1233 return -1;
1234 }
1235
1236 }
1237
1238 /* finish filling in fields */
1239
1240 ip_look->set_flags |= sflag;
1241
1242 if (sflag & FT_TAG_SET_SRC_TAG)
1243 ip_look->src_tag = tag;
1244
1245 if (sflag & FT_TAG_OR_SRC_TAG)
1246 ip_look->src_tag |= tag;
1247
1248 if (sflag & FT_TAG_SET_DST_TAG)
1249 ip_look->dst_tag = tag;
1250
1251 if (sflag & FT_TAG_OR_DST_TAG)
1252 ip_look->dst_tag |= tag;
1253
1254 }
1255
1256 return 0;
1257
1258 } /* parse_action_match */
1259
1260 /*
1261 * function: parse_def
1262 *
1263 * process the 'definition' line. Each definition has a unique name which
1264 * is added to the fttag->defs linked list. The current definition is
1265 * updated in lp.
1266 *
1267 * returns: 0 ok
1268 * <0 fail
1269 */
parse_def(struct line_parser * lp,struct fttag * fttag)1270 int parse_def(struct line_parser *lp, struct fttag *fttag)
1271 {
1272 char *c;
1273 struct fttag_def *ftd;
1274
1275 NEXT_WORD(&lp->buf, c);
1276
1277 if (!c) {
1278 fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno);
1279 return -1;
1280 }
1281
1282 /* check if it exists */
1283 FT_SLIST_FOREACH(ftd, &fttag->defs, chain) {
1284
1285 if (!strcasecmp(c, ftd->name)) {
1286 fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname,
1287 lp->lineno, c);
1288 return -1;
1289 }
1290
1291 }
1292
1293 /* no, add a new entry to the list */
1294 if (!(ftd = (struct fttag_def*)malloc(sizeof
1295 (struct fttag_def)))) {
1296 fterr_warn("malloc()");
1297 return -1;
1298 }
1299
1300 bzero(ftd, sizeof *ftd);
1301
1302 FT_STAILQ_INIT(&ftd->terms);
1303
1304 if (!(ftd->name = (char*)malloc(strlen(c)+1))) {
1305 fterr_warn("malloc()");
1306 free(ftd);
1307 return -1;
1308 }
1309
1310 strcpy(ftd->name, c);
1311
1312 FT_SLIST_INSERT_HEAD(&fttag->defs, ftd, chain);
1313
1314 lp->state = PARSE_STATE_DEFINITION;
1315 lp->cur_def = ftd;
1316
1317 return 0;
1318
1319 } /* parse_def */
1320
1321 /*
1322 * function: parse_def_term
1323 *
1324 * process the term line. Each definition has a list of terms, the
1325 * terms have a common input, output, and exporter IP filter and
1326 * may have one or more actions. Without an action a term has
1327 * no purpose.
1328 *
1329 * returns: 0 ok
1330 * <0 fail
1331 */
parse_def_term(struct line_parser * lp,struct fttag * fttag)1332 int parse_def_term(struct line_parser *lp, struct fttag *fttag)
1333 {
1334 struct fttag_def_term *ftdt;
1335
1336 if (!lp->cur_def) {
1337 fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno);
1338 return -1;
1339 }
1340
1341 /* no, add a new term entry to this definition */
1342 if (!(ftdt = (struct fttag_def_term*)malloc(sizeof *ftdt))) {
1343 fterr_warn("malloc()");
1344 return -1;
1345 }
1346
1347 bzero(ftdt, sizeof *ftdt);
1348
1349 FT_STAILQ_INIT(&ftdt->actions);
1350
1351 FT_STAILQ_INSERT_TAIL(&lp->cur_def->terms, ftdt, chain);
1352
1353 lp->cur_def_term = ftdt;
1354
1355 return 0;
1356
1357 } /* parse_def_term */
1358
1359 /*
1360 * function: parse_def_exporter
1361 *
1362 * process the 'exporter' line.
1363 *
1364 * returns: 0 ok
1365 * <0 fail
1366 */
parse_def_exporter(struct line_parser * lp,struct fttag * fttag)1367 int parse_def_exporter(struct line_parser *lp, struct fttag *fttag)
1368 {
1369 char *c;
1370
1371 if (!lp->cur_def_term) {
1372 fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1373 return -1;
1374 }
1375
1376 NEXT_WORD(&lp->buf, c);
1377
1378 if (!c) {
1379 fterr_warnx("%s line %d: Expecting exporter.", lp->fname, lp->lineno);
1380 return -1;
1381 }
1382
1383 if (lp->cur_def_term->flags & FT_TAG_DEF_FILTER_EXPORTER) {
1384 fterr_warnx("%s line %d: Exporter previously defined.", lp->fname,
1385 lp->lineno);
1386 return -1;
1387 }
1388
1389 lp->cur_def_term->exporter_ip = scan_ip(c);
1390
1391 lp->cur_def_term->flags |= FT_TAG_DEF_FILTER_EXPORTER;
1392
1393 return 0;
1394
1395 } /* parse_def_exporter */
1396
1397 /*
1398 * function: parse_def_input_filter
1399 *
1400 * process the 'input-filter' line.
1401 *
1402 * returns: 0 ok
1403 * <0 fail
1404 */
parse_def_input_filter(struct line_parser * lp,struct fttag * fttag)1405 int parse_def_input_filter(struct line_parser *lp, struct fttag *fttag)
1406 {
1407 char *c;
1408
1409 if (!lp->cur_def_term) {
1410 fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1411 return -1;
1412 }
1413
1414 NEXT_WORD(&lp->buf, c);
1415
1416 if (!c) {
1417 fterr_warnx("%s line %d: Expecting filter list.", lp->fname, lp->lineno);
1418 return -1;
1419 }
1420
1421 if (lp->cur_def_term->flags & FT_TAG_DEF_FILTER_INPUT) {
1422 fterr_warnx("%s line %d: Input filter previously defined.", lp->fname,
1423 lp->lineno);
1424 return -1;
1425 }
1426
1427 if (load_lookup(c, 65536, lp->cur_def_term->in_tbl)) {
1428 fterr_warnx("load_lookup(): failed");
1429 return -1;
1430 }
1431
1432 lp->cur_def_term->flags |= FT_TAG_DEF_FILTER_INPUT;
1433
1434 return 0;
1435
1436 } /* parse_def_input_filter */
1437
1438 /*
1439 * function: parse_def_output_filter
1440 *
1441 * process the 'output-filter' line.
1442 *
1443 * returns: 0 ok
1444 * <0 fail
1445 */
parse_def_output_filter(struct line_parser * lp,struct fttag * fttag)1446 int parse_def_output_filter(struct line_parser *lp, struct fttag *fttag)
1447 {
1448 char *c;
1449
1450 if (!lp->cur_def_term) {
1451 fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1452 return -1;
1453 }
1454
1455 NEXT_WORD(&lp->buf, c);
1456
1457 if (!c) {
1458 fterr_warnx("%s line %d: Expecting filter list.", lp->fname, lp->lineno);
1459 return -1;
1460 }
1461
1462 if (lp->cur_def_term->flags & FT_TAG_DEF_FILTER_OUTPUT) {
1463 fterr_warnx("%s line %d: Output filter previously defined.", lp->fname,
1464 lp->lineno);
1465 return -1;
1466 }
1467
1468 if (load_lookup(c, 65536, lp->cur_def_term->out_tbl)) {
1469 fterr_warnx("load_lookup(): failed");
1470 return -1;
1471 }
1472
1473 lp->cur_def_term->flags |= FT_TAG_DEF_FILTER_OUTPUT;
1474
1475 return 0;
1476
1477 } /* parse_def_output_filter */
1478
1479 /*
1480 * function: parse_def_action
1481 *
1482 * foreach action listed, add it to a linked list of actions for the
1483 * definition. Note resolve_actions() must be called before the actions
1484 * are valid.
1485 *
1486 * returns: 0 ok
1487 * <0 fail
1488 */
parse_def_action(struct line_parser * lp,struct fttag * fttag)1489 int parse_def_action(struct line_parser *lp, struct fttag *fttag)
1490 {
1491 struct fttag_def_term_actions *ftdta;
1492 char *c;
1493
1494 if (!lp->cur_def_term) {
1495 fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1496 return -1;
1497 }
1498
1499 NEXT_WORD(&lp->buf, c);
1500
1501 if (!c) {
1502 fterr_warnx("%s line %d: Expecting action.", lp->fname, lp->lineno);
1503 return -1;
1504 }
1505
1506 /* add a new entry to the list */
1507 if (!(ftdta = (struct fttag_def_term_actions*)malloc(sizeof *ftdta))) {
1508 fterr_warn("malloc()");
1509 return -1;
1510 }
1511
1512 bzero(ftdta, sizeof *ftdta);
1513
1514 if (!(ftdta->name = (char*)malloc(strlen(c)+1))) {
1515 fterr_warn("malloc()");
1516 free(ftdta);
1517 return -1;
1518 }
1519 strcpy(ftdta->name, c);
1520
1521 FT_STAILQ_INSERT_TAIL(&lp->cur_def_term->actions, ftdta, chain);
1522
1523 /* resolve the ftdta->action later in resolve_actions */
1524
1525 return 0;
1526
1527 } /* parse_def_action */
1528
1529 /*
1530 * function: resolve_actions
1531 *
1532 * The parser points to the name of the action in the definition to allow
1533 * for definitions to be defined before actions in the config file. This
1534 * fixes the pointers so the definitions point to the actions
1535 *
1536 * returns: 0 ok
1537 * <0 fail (an action could not be resolved)
1538 */
resolve_actions(struct fttag * fttag)1539 int resolve_actions(struct fttag *fttag)
1540 {
1541 struct fttag_def *ftd;
1542 struct fttag_def_term *ftdt;
1543 struct fttag_def_term_actions *ftdta;
1544 struct fttag_action *fta;
1545 int i, found = 0;
1546
1547 /* foreach definition */
1548 FT_SLIST_FOREACH(ftd, &fttag->defs, chain) {
1549
1550 /* foreach term in the definition */
1551 FT_STAILQ_FOREACH(ftdt, &ftd->terms, chain) {
1552
1553 /*
1554 * pre-init filter to all 1's to minimize test in eval later
1555 */
1556
1557 if (!(ftdt->flags & FT_TAG_DEF_FILTER_INPUT))
1558 for (i = 0; i < 65536; ++i)
1559 ftdt->in_tbl[i] = 1;
1560
1561 if (!(ftdt->flags & FT_TAG_DEF_FILTER_OUTPUT))
1562 for (i = 0; i < 65536; ++i)
1563 ftdt->out_tbl[i] = 1;
1564
1565 /* foreach action in the term */
1566 FT_STAILQ_FOREACH(ftdta, &ftdt->actions, chain) {
1567
1568 found = 0;
1569
1570 /* foreach action */
1571 FT_SLIST_FOREACH(fta, &fttag->actions, chain) {
1572
1573 if (!(strcasecmp(fta->name, ftdta->name))) {
1574
1575 ftdta->action = fta;
1576 found = 1;
1577 break;
1578
1579 }
1580
1581 }
1582
1583 }
1584
1585 if (!found) {
1586
1587 fterr_warnx("Unable to resolve action \"%s\" in tag-definition \"%s\".", ftdta->name, ftd->name);
1588 return -1;
1589
1590 }
1591
1592 }
1593
1594 }
1595
1596 return 0;
1597
1598 } /* resolve actions */
1599
1600 /*
1601 * function: fttag_free
1602 *
1603 * free resources allocated by fttag_load()
1604 *
1605 */
fttag_free(struct fttag * fttag)1606 void fttag_free(struct fttag *fttag)
1607 {
1608 struct fttag_action *fta;
1609 struct fttag_def *ftd;
1610 struct fttag_def_term *ftdt;
1611 struct fttag_def_term_actions *ftdta;
1612
1613 /* foreach action, remove the action and associated storge */
1614 while (!FT_SLIST_EMPTY(&fttag->actions)) {
1615
1616 fta = FT_SLIST_FIRST(&fttag->actions);
1617
1618 FT_SLIST_REMOVE_HEAD(&fttag->actions, chain);
1619
1620 if (fta->type & FT_TAG_TYPE_MATCH_AS)
1621 free(fta->look);
1622 else if (fta->type & FT_TAG_TYPE_MATCH_NEXTHOP)
1623 ftchash_free(fta->look);
1624 else if (fta->type & FT_TAG_TYPE_MATCH_EXPORTER)
1625 ftchash_free(fta->look);
1626 else if (fta->type & FT_TAG_TYPE_MATCH_IP)
1627 ftchash_free(fta->look);
1628 else if (fta->type & FT_TAG_TYPE_MATCH_PREFIX) {
1629 rhead = fta->look;
1630 rhead->rnh_walktree(rhead, walk_free, 0);
1631 }
1632
1633 free(fta->name);
1634 free(fta);
1635
1636 } /* while */
1637
1638 /* foreach definition, remove the definition and associated storage */
1639 while (!FT_SLIST_EMPTY(&fttag->defs)) {
1640
1641 ftd = FT_SLIST_FIRST(&fttag->defs);
1642
1643 FT_SLIST_REMOVE_HEAD(&fttag->defs, chain);
1644
1645 /* foreach term in the definition */
1646 while (!FT_STAILQ_EMPTY(&ftd->terms)) {
1647
1648 ftdt = FT_STAILQ_FIRST(&ftd->terms);
1649
1650 while (!FT_STAILQ_EMPTY(&ftdt->actions)) {
1651
1652 ftdta = FT_STAILQ_FIRST(&ftdt->actions);
1653
1654 if (ftdta->name)
1655 free(ftdta->name);
1656
1657 FT_STAILQ_REMOVE_HEAD(&ftdt->actions, chain);
1658
1659 free(ftdta);
1660
1661 }
1662
1663 FT_STAILQ_REMOVE_HEAD(&ftd->terms, chain);
1664
1665 free (ftdt);
1666
1667 }
1668
1669 free(ftd->name);
1670 free(ftd);
1671
1672 } /* while */
1673
1674 } /* fttag_free */
1675
1676 /*
1677 * function: fttag_def_eval
1678 *
1679 * perform tag actions on a flow
1680 *
1681 * run down each term in the definition
1682 * evaluate the filter, if okay
1683 * run every action
1684 *
1685 * the filter is activated by
1686 * FT_TAG_DEF_FILTER_INPUT - check input
1687 * FT_TAG_DEF_FILTER_OUTPUT check output
1688 * FT_TAG_DEF_FILTER_EXPORTER check exporter
1689 *
1690 *
1691 * returns 0
1692 */
fttag_def_eval(struct fttag_def * ftd,struct fts3rec_v1005 * rec)1693 int fttag_def_eval(struct fttag_def *ftd,
1694 struct fts3rec_v1005 *rec)
1695 {
1696 struct fttag_def_term *ftdt;
1697 struct fttag_def_term_actions *ftdta;
1698 struct fttag_action *fta;
1699
1700 /* foreach term in the definition */
1701 FT_STAILQ_FOREACH(ftdt, &ftd->terms, chain) {
1702
1703 /* in_tbl is preloaded with "permit any" so don't check the flags bit */
1704 if (!ftdt->in_tbl[rec->input])
1705 continue;
1706
1707 /* out_tbl is preloaded with "permit any" so don't check the flags bit */
1708 if (!ftdt->out_tbl[rec->output])
1709 continue;
1710
1711 if (ftdt->flags & FT_TAG_DEF_FILTER_EXPORTER)
1712 if (ftdt->exporter_ip != rec->exaddr)
1713 continue;
1714
1715 /* for every action chained to this term */
1716 FT_STAILQ_FOREACH(ftdta, &ftdt->actions, chain) {
1717
1718 /* the action */
1719 fta = ftdta->action;
1720
1721 /* based on the type do the action if a match is made */
1722 fta->eval(fta, rec);
1723
1724 } /* foreach action references by the term */
1725
1726 } /* foreach term */
1727
1728 return 0;
1729
1730 } /* fttag_def_eval */
1731
eval_match_src_as(struct fttag_action * fta,struct fts3rec_v1005 * rec)1732 static void eval_match_src_as(struct fttag_action *fta,
1733 struct fts3rec_v1005 *rec)
1734 {
1735 struct fttag_as_look *as_look;
1736 uint16_t set_tmp;
1737
1738 as_look = fta->look;
1739
1740 set_tmp = as_look->set_flags_lookup[rec->src_as];
1741
1742 if (set_tmp & FT_TAG_SET_DST_TAG)
1743 rec->dst_tag = as_look->dst_tag_lookup[rec->src_as];
1744 else if (set_tmp & FT_TAG_OR_DST_TAG)
1745 rec->dst_tag |= as_look->dst_tag_lookup[rec->src_as];
1746
1747 if (set_tmp & FT_TAG_SET_SRC_TAG)
1748 rec->src_tag = as_look->src_tag_lookup[rec->src_as];
1749 if (set_tmp & FT_TAG_OR_SRC_TAG)
1750 rec->src_tag |= as_look->src_tag_lookup[rec->src_as];
1751
1752 } /* eval_match_src_as */
1753
eval_match_dst_as(struct fttag_action * fta,struct fts3rec_v1005 * rec)1754 static void eval_match_dst_as(struct fttag_action *fta,
1755 struct fts3rec_v1005 *rec)
1756 {
1757 struct fttag_as_look *as_look;
1758 uint16_t set_tmp;
1759
1760 as_look = fta->look;
1761
1762 set_tmp = as_look->set_flags_lookup[rec->dst_as];
1763
1764 if (set_tmp & FT_TAG_SET_DST_TAG)
1765 rec->dst_tag = as_look->dst_tag_lookup[rec->dst_as];
1766 else if (set_tmp & FT_TAG_OR_DST_TAG)
1767 rec->dst_tag |= as_look->dst_tag_lookup[rec->dst_as];
1768
1769 if (set_tmp & FT_TAG_SET_SRC_TAG)
1770 rec->src_tag = as_look->src_tag_lookup[rec->dst_as];
1771 if (set_tmp & FT_TAG_OR_SRC_TAG)
1772 rec->src_tag |= as_look->src_tag_lookup[rec->dst_as];
1773
1774 } /* eval_match_dst_as */
1775
eval_match_src_prefix(struct fttag_action * fta,struct fts3rec_v1005 * rec)1776 static void eval_match_src_prefix(struct fttag_action *fta,
1777 struct fts3rec_v1005 *rec)
1778 {
1779 struct radix_sockaddr_in dst_sock;
1780 struct fttag_prefix_look *prefix_look;
1781 struct radix_node_head *rhead;
1782 uint16_t set_tmp;
1783
1784 rhead = fta->look;
1785
1786 dst_sock.sin_addr.s_addr = rec->srcaddr;
1787 dst_sock.sin_len = sizeof (struct radix_sockaddr_in);
1788 dst_sock.sin_family = AF_INET;
1789
1790 prefix_look = (struct fttag_prefix_look *)
1791 rhead->rnh_matchaddr(&dst_sock, rhead);
1792
1793 if (prefix_look) {
1794
1795 set_tmp = prefix_look->set_flags;
1796
1797 if (set_tmp & FT_TAG_SET_DST_TAG)
1798 rec->dst_tag = prefix_look->dst_tag;
1799 else if (set_tmp & FT_TAG_OR_DST_TAG)
1800 rec->dst_tag |= prefix_look->dst_tag;
1801
1802 if (set_tmp & FT_TAG_SET_SRC_TAG)
1803 rec->src_tag = prefix_look->src_tag;
1804 else if (set_tmp & FT_TAG_OR_SRC_TAG)
1805 rec->src_tag |= prefix_look->src_tag;
1806
1807 }
1808
1809 } /* eval_match_src_prefix */
1810
eval_match_dst_prefix(struct fttag_action * fta,struct fts3rec_v1005 * rec)1811 static void eval_match_dst_prefix(struct fttag_action *fta,
1812 struct fts3rec_v1005 *rec)
1813 {
1814 struct radix_sockaddr_in dst_sock;
1815 struct fttag_prefix_look *prefix_look;
1816 struct radix_node_head *rhead;
1817 uint16_t set_tmp;
1818
1819 rhead = fta->look;
1820
1821 dst_sock.sin_addr.s_addr = rec->dstaddr;
1822 dst_sock.sin_len = sizeof (struct radix_sockaddr_in);
1823 dst_sock.sin_family = AF_INET;
1824
1825 prefix_look = (struct fttag_prefix_look *)
1826 rhead->rnh_matchaddr(&dst_sock, rhead);
1827
1828 if (prefix_look) {
1829
1830 set_tmp = prefix_look->set_flags;
1831
1832 if (set_tmp & FT_TAG_SET_DST_TAG)
1833 rec->dst_tag = prefix_look->dst_tag;
1834 else if (set_tmp & FT_TAG_OR_DST_TAG)
1835 rec->dst_tag |= prefix_look->dst_tag;
1836
1837 if (set_tmp & FT_TAG_SET_SRC_TAG)
1838 rec->src_tag = prefix_look->src_tag;
1839 else if (set_tmp & FT_TAG_OR_SRC_TAG)
1840 rec->src_tag |= prefix_look->src_tag;
1841
1842 }
1843
1844 } /* eval_match_dst_prefix */
1845
eval_match_nexthop(struct fttag_action * fta,struct fts3rec_v1005 * rec)1846 static void eval_match_nexthop(struct fttag_action *fta,
1847 struct fts3rec_v1005 *rec)
1848 {
1849 struct ftchash *ftch;
1850 uint32_t hash, ipaddr;
1851 struct fttag_next_hop_look *nh_look;
1852 uint16_t set_tmp;
1853
1854 ftch = fta->look;
1855 ipaddr = rec->nexthop;
1856
1857 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1858 hash = (hash>>8) ^ (hash & 0xFF);
1859
1860 /* lookup next hop */
1861 nh_look = ftchash_lookup(ftch, &ipaddr, hash);
1862
1863 if (nh_look) {
1864
1865 set_tmp = nh_look->set_flags;
1866
1867 if (set_tmp & FT_TAG_SET_DST_TAG)
1868 rec->dst_tag = nh_look->dst_tag;
1869 else if (set_tmp & FT_TAG_OR_DST_TAG)
1870 rec->dst_tag |= nh_look->dst_tag;
1871
1872 if (set_tmp & FT_TAG_SET_SRC_TAG)
1873 rec->src_tag = nh_look->src_tag;
1874 else if (set_tmp & FT_TAG_OR_SRC_TAG)
1875 rec->src_tag |= nh_look->src_tag;
1876
1877 }
1878
1879 } /* eval_match_nexthop */
1880
eval_match_exporter(struct fttag_action * fta,struct fts3rec_v1005 * rec)1881 static void eval_match_exporter(struct fttag_action *fta,
1882 struct fts3rec_v1005 *rec)
1883 {
1884 struct ftchash *ftch;
1885 uint32_t hash, ipaddr;
1886 struct fttag_exporter_look *exporter_look;
1887 uint16_t set_tmp;
1888
1889 ftch = fta->look;
1890 ipaddr = rec->exaddr;
1891
1892 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1893 hash = (hash>>8) ^ (hash & 0xFF);
1894
1895 /* lookup next hop */
1896 exporter_look = ftchash_lookup(ftch, &ipaddr, hash);
1897
1898 if (exporter_look) {
1899
1900 set_tmp = exporter_look->set_flags;
1901
1902
1903 if (set_tmp & FT_TAG_SET_DST_TAG)
1904 rec->dst_tag = exporter_look->dst_tag;
1905 else if (set_tmp & FT_TAG_OR_DST_TAG)
1906 rec->dst_tag |= exporter_look->dst_tag;
1907
1908 if (set_tmp & FT_TAG_SET_SRC_TAG)
1909 rec->src_tag = exporter_look->src_tag;
1910 else if (set_tmp & FT_TAG_OR_SRC_TAG)
1911 rec->src_tag |= exporter_look->src_tag;
1912
1913 }
1914
1915 } /* eval_match_exporter */
1916
eval_match_src_ip(struct fttag_action * fta,struct fts3rec_v1005 * rec)1917 static void eval_match_src_ip(struct fttag_action *fta,
1918 struct fts3rec_v1005 *rec)
1919 {
1920 struct ftchash *ftch;
1921 uint32_t hash, ipaddr;
1922 struct fttag_ip_look *ip_look;
1923 uint16_t set_tmp;
1924
1925 ftch = fta->look;
1926 ipaddr = rec->srcaddr;
1927
1928 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1929 hash = (hash>>8) ^ (hash & 0xFF);
1930
1931 /* lookup next hop */
1932 ip_look = ftchash_lookup(ftch, &ipaddr, hash);
1933
1934 if (ip_look) {
1935
1936 set_tmp = ip_look->set_flags;
1937
1938
1939 if (set_tmp & FT_TAG_SET_DST_TAG)
1940 rec->dst_tag = ip_look->dst_tag;
1941 else if (set_tmp & FT_TAG_OR_DST_TAG)
1942 rec->dst_tag |= ip_look->dst_tag;
1943
1944 if (set_tmp & FT_TAG_SET_SRC_TAG)
1945 rec->src_tag = ip_look->src_tag;
1946 else if (set_tmp & FT_TAG_OR_SRC_TAG)
1947 rec->src_tag |= ip_look->src_tag;
1948
1949 }
1950
1951 } /* eval_match_src_ip */
1952
eval_match_dst_ip(struct fttag_action * fta,struct fts3rec_v1005 * rec)1953 static void eval_match_dst_ip(struct fttag_action *fta,
1954 struct fts3rec_v1005 *rec)
1955 {
1956 struct ftchash *ftch;
1957 uint32_t hash, ipaddr;
1958 struct fttag_ip_look *ip_look;
1959 uint16_t set_tmp;
1960
1961 ftch = fta->look;
1962 ipaddr = rec->dstaddr;
1963
1964 hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1965 hash = (hash>>8) ^ (hash & 0xFF);
1966
1967 /* lookup next hop */
1968 ip_look = ftchash_lookup(ftch, &ipaddr, hash);
1969
1970 if (ip_look) {
1971
1972 set_tmp = ip_look->set_flags;
1973
1974
1975 if (set_tmp & FT_TAG_SET_DST_TAG)
1976 rec->dst_tag = ip_look->dst_tag;
1977 else if (set_tmp & FT_TAG_OR_DST_TAG)
1978 rec->dst_tag |= ip_look->dst_tag;
1979
1980 if (set_tmp & FT_TAG_SET_SRC_TAG)
1981 rec->src_tag = ip_look->src_tag;
1982 else if (set_tmp & FT_TAG_OR_SRC_TAG)
1983 rec->src_tag |= ip_look->src_tag;
1984
1985 }
1986
1987 } /* eval_match_dst_ip */
1988
eval_match_prefix(struct fttag_action * fta,struct fts3rec_v1005 * rec)1989 static void eval_match_prefix(struct fttag_action *fta,
1990 struct fts3rec_v1005 *rec)
1991 {
1992 eval_match_src_prefix(fta, rec);
1993 eval_match_dst_prefix(fta, rec);
1994 } /* eval_match_prefix */
1995
eval_match_as(struct fttag_action * fta,struct fts3rec_v1005 * rec)1996 static void eval_match_as(struct fttag_action *fta,
1997 struct fts3rec_v1005 *rec)
1998 {
1999 eval_match_src_as(fta, rec);
2000 eval_match_dst_as(fta, rec);
2001 } /* eval_match_as */
2002
eval_match_tcp_src_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2003 static void eval_match_tcp_src_port(struct fttag_action *fta,
2004 struct fts3rec_v1005 *rec)
2005 {
2006 struct fttag_port_look *port_look;
2007 uint16_t set_tmp;
2008
2009 port_look = fta->look;
2010
2011 /* only TCP here */
2012 if (rec->prot != 6)
2013 return;
2014
2015 set_tmp = port_look->set_flags_lookup[rec->srcport];
2016
2017 if (set_tmp & FT_TAG_SET_DST_TAG)
2018 rec->dst_tag = port_look->dst_tag_lookup[rec->srcport];
2019 else if (set_tmp & FT_TAG_OR_DST_TAG)
2020 rec->dst_tag |= port_look->dst_tag_lookup[rec->srcport];
2021
2022 if (set_tmp & FT_TAG_SET_SRC_TAG)
2023 rec->src_tag = port_look->src_tag_lookup[rec->srcport];
2024 if (set_tmp & FT_TAG_OR_SRC_TAG)
2025 rec->src_tag |= port_look->src_tag_lookup[rec->srcport];
2026
2027 } /* eval_match_tcp_src_port */
2028
eval_match_tcp_dst_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2029 static void eval_match_tcp_dst_port(struct fttag_action *fta,
2030 struct fts3rec_v1005 *rec)
2031 {
2032 struct fttag_port_look *port_look;
2033 uint16_t set_tmp;
2034
2035 port_look = fta->look;
2036
2037 /* only TCP here */
2038 if (rec->prot != 6)
2039 return;
2040
2041 set_tmp = port_look->set_flags_lookup[rec->dstport];
2042
2043 if (set_tmp & FT_TAG_SET_DST_TAG)
2044 rec->dst_tag = port_look->dst_tag_lookup[rec->dstport];
2045 else if (set_tmp & FT_TAG_OR_DST_TAG)
2046 rec->dst_tag |= port_look->dst_tag_lookup[rec->dstport];
2047
2048 if (set_tmp & FT_TAG_SET_SRC_TAG)
2049 rec->src_tag = port_look->src_tag_lookup[rec->dstport];
2050 if (set_tmp & FT_TAG_OR_SRC_TAG)
2051 rec->src_tag |= port_look->src_tag_lookup[rec->dstport];
2052
2053 } /* eval_match_tcp_dst_port */
2054
eval_match_udp_src_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2055 static void eval_match_udp_src_port(struct fttag_action *fta,
2056 struct fts3rec_v1005 *rec)
2057 {
2058 struct fttag_port_look *port_look;
2059 uint16_t set_tmp;
2060
2061 port_look = fta->look;
2062
2063 /* only UDP here */
2064 if (rec->prot != 17)
2065 return;
2066
2067 set_tmp = port_look->set_flags_lookup[rec->srcport];
2068
2069 if (set_tmp & FT_TAG_SET_DST_TAG)
2070 rec->dst_tag = port_look->dst_tag_lookup[rec->srcport];
2071 else if (set_tmp & FT_TAG_OR_DST_TAG)
2072 rec->dst_tag |= port_look->dst_tag_lookup[rec->srcport];
2073
2074 if (set_tmp & FT_TAG_SET_SRC_TAG)
2075 rec->src_tag = port_look->src_tag_lookup[rec->srcport];
2076 if (set_tmp & FT_TAG_OR_SRC_TAG)
2077 rec->src_tag |= port_look->src_tag_lookup[rec->srcport];
2078
2079 } /* eval_match_udp_src_port */
2080
eval_match_udp_dst_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2081 static void eval_match_udp_dst_port(struct fttag_action *fta,
2082 struct fts3rec_v1005 *rec)
2083 {
2084 struct fttag_port_look *port_look;
2085 uint16_t set_tmp;
2086
2087 port_look = fta->look;
2088
2089 /* only UDP here */
2090 if (rec->prot != 17)
2091 return;
2092
2093 set_tmp = port_look->set_flags_lookup[rec->dstport];
2094
2095 if (set_tmp & FT_TAG_SET_DST_TAG)
2096 rec->dst_tag = port_look->dst_tag_lookup[rec->dstport];
2097 else if (set_tmp & FT_TAG_OR_DST_TAG)
2098 rec->dst_tag |= port_look->dst_tag_lookup[rec->dstport];
2099
2100 if (set_tmp & FT_TAG_SET_SRC_TAG)
2101 rec->src_tag = port_look->src_tag_lookup[rec->dstport];
2102 if (set_tmp & FT_TAG_OR_SRC_TAG)
2103 rec->src_tag |= port_look->src_tag_lookup[rec->dstport];
2104
2105 } /* eval_match_udp_dst_port */
2106
eval_match_tcp_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2107 static void eval_match_tcp_port(struct fttag_action *fta,
2108 struct fts3rec_v1005 *rec)
2109 {
2110 eval_match_tcp_src_port(fta, rec);
2111 eval_match_tcp_dst_port(fta, rec);
2112 } /* eval_match_tcp_port */
2113
eval_match_udp_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2114 static void eval_match_udp_port(struct fttag_action *fta,
2115 struct fts3rec_v1005 *rec)
2116 {
2117 eval_match_udp_src_port(fta, rec);
2118 eval_match_udp_dst_port(fta, rec);
2119 } /* eval_match_udp_port */
2120
eval_match_in_interface(struct fttag_action * fta,struct fts3rec_v1005 * rec)2121 static void eval_match_in_interface(struct fttag_action *fta,
2122 struct fts3rec_v1005 *rec)
2123 {
2124 struct fttag_interface_look *interface_look;
2125 uint16_t set_tmp;
2126
2127 interface_look = fta->look;
2128
2129 set_tmp = interface_look->set_flags_lookup[rec->input];
2130
2131 if (set_tmp & FT_TAG_SET_DST_TAG)
2132 rec->dst_tag = interface_look->dst_tag_lookup[rec->input];
2133 else if (set_tmp & FT_TAG_OR_DST_TAG)
2134 rec->dst_tag |= interface_look->dst_tag_lookup[rec->input];
2135
2136 if (set_tmp & FT_TAG_SET_SRC_TAG)
2137 rec->src_tag = interface_look->src_tag_lookup[rec->input];
2138 if (set_tmp & FT_TAG_OR_SRC_TAG)
2139 rec->src_tag |= interface_look->src_tag_lookup[rec->input];
2140
2141 } /* eval_match_in_interface */
2142
eval_match_out_interface(struct fttag_action * fta,struct fts3rec_v1005 * rec)2143 static void eval_match_out_interface(struct fttag_action *fta,
2144 struct fts3rec_v1005 *rec)
2145 {
2146 struct fttag_interface_look *interface_look;
2147 uint16_t set_tmp;
2148
2149 interface_look = fta->look;
2150
2151 set_tmp = interface_look->set_flags_lookup[rec->output];
2152
2153 if (set_tmp & FT_TAG_SET_DST_TAG)
2154 rec->dst_tag = interface_look->dst_tag_lookup[rec->output];
2155 else if (set_tmp & FT_TAG_OR_DST_TAG)
2156 rec->dst_tag |= interface_look->dst_tag_lookup[rec->output];
2157
2158 if (set_tmp & FT_TAG_SET_SRC_TAG)
2159 rec->src_tag = interface_look->src_tag_lookup[rec->output];
2160 if (set_tmp & FT_TAG_OR_SRC_TAG)
2161 rec->src_tag |= interface_look->src_tag_lookup[rec->output];
2162
2163 } /* eval_match_out_interface */
2164
eval_match_interface(struct fttag_action * fta,struct fts3rec_v1005 * rec)2165 static void eval_match_interface(struct fttag_action *fta,
2166 struct fts3rec_v1005 *rec)
2167 {
2168 eval_match_in_interface(fta, rec);
2169 eval_match_out_interface(fta, rec);
2170 } /* eval_match_interface */
2171
eval_match_ip(struct fttag_action * fta,struct fts3rec_v1005 * rec)2172 static void eval_match_ip(struct fttag_action *fta,
2173 struct fts3rec_v1005 *rec)
2174 {
2175 eval_match_src_ip(fta, rec);
2176 eval_match_dst_ip(fta, rec);
2177 } /* eval_match_ip */
2178
eval_match_tos(struct fttag_action * fta,struct fts3rec_v1005 * rec)2179 static void eval_match_tos(struct fttag_action *fta,
2180 struct fts3rec_v1005 *rec)
2181 {
2182 struct fttag_tos_look *tos_look;
2183 uint16_t set_tmp;
2184
2185 tos_look = fta->look;
2186
2187 set_tmp = tos_look->set_flags_lookup[rec->tos];
2188
2189 if (set_tmp & FT_TAG_SET_DST_TAG)
2190 rec->dst_tag = tos_look->dst_tag_lookup[rec->tos];
2191 else if (set_tmp & FT_TAG_OR_DST_TAG)
2192 rec->dst_tag |= tos_look->dst_tag_lookup[rec->tos];
2193
2194 if (set_tmp & FT_TAG_SET_SRC_TAG)
2195 rec->src_tag = tos_look->src_tag_lookup[rec->tos];
2196 if (set_tmp & FT_TAG_OR_SRC_TAG)
2197 rec->src_tag |= tos_look->src_tag_lookup[rec->tos];
2198
2199 } /* eval_match_tos */
2200
eval_match_any(struct fttag_action * fta,struct fts3rec_v1005 * rec)2201 static void eval_match_any(struct fttag_action *fta,
2202 struct fts3rec_v1005 *rec)
2203 {
2204 struct fttag_any_look *any_look;
2205 uint16_t set_tmp;
2206
2207 any_look = fta->look;
2208
2209 set_tmp = any_look->set_flags;
2210
2211 if (set_tmp & FT_TAG_SET_DST_TAG)
2212 rec->dst_tag = any_look->dst_tag;
2213 else if (set_tmp & FT_TAG_OR_DST_TAG)
2214 rec->dst_tag |= any_look->dst_tag;
2215
2216 if (set_tmp & FT_TAG_SET_SRC_TAG)
2217 rec->src_tag = any_look->src_tag;
2218 if (set_tmp & FT_TAG_OR_SRC_TAG)
2219 rec->src_tag |= any_look->src_tag;
2220
2221 } /* eval_match_any */
2222
2223
walk_free(struct radix_node * rn,struct walkarg * UNUSED)2224 static int walk_free(struct radix_node *rn, struct walkarg *UNUSED)
2225 {
2226 struct fttag_prefix_look *r;
2227 struct radix_sockaddr_in sock1, sock2;
2228
2229 r = (struct fttag_prefix_look*)rn;
2230 bzero(&sock1, sizeof sock1);
2231 bzero(&sock2, sizeof sock2);
2232
2233 sock1.sin_addr.s_addr = r->addr.sin_addr.s_addr;
2234 sock1.sin_len = sizeof sock1;
2235 sock1.sin_family = AF_INET;
2236
2237 sock2.sin_addr.s_addr = (!r->masklen) ? 0: mask_lookup[r->masklen];
2238 sock2.sin_len = sizeof sock2;
2239 sock2.sin_family = AF_INET;
2240
2241 if (r != (struct fttag_prefix_look*)rhead->rnh_deladdr(&sock1,
2242 &sock2, rhead))
2243 fterr_errx(1, "rn_deladdr(): failed.");
2244 else
2245 free(r);
2246
2247 return 0;
2248 } /* walk_free */
2249
2250