📄 fttag.c
字号:
/* * Copyright (c) 2001 Mark Fullmer and The Ohio State University * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: fttag.c,v 1.15 2003/02/13 02:38:42 maf Exp $ */#include "ftconfig.h"#include "ftlib.h"#include <sys/time.h>#include <sys/types.h>#include <sys/uio.h>#include <sys/socket.h>#include <sys/resource.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/stat.h>#include <syslog.h>#include <dirent.h>#include <limits.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#include <fcntl.h>#include <zlib.h>#if HAVE_STRINGS_H #include <strings.h>#endif#if HAVE_STRING_H #include <string.h>#endif#if !HAVE_STRSEP char *strsep (char **, const char *);#endifextern int max_keylen;extern u_int32 mask_lookup[];static struct radix_node_head *rhead;struct line_parser { struct fttag_action *cur_action; struct fttag_def *cur_def; struct fttag_def_term *cur_def_term; int state, type; int lineno; char *buf, *fname;};static int parse_action(struct line_parser *lp, struct fttag *fttag);static int parse_action_type(struct line_parser *lp, struct fttag *fttag);static int parse_action_match(struct line_parser *lp, struct fttag *fttag);static int parse_def(struct line_parser *lp, struct fttag *fttag);static int parse_def_exporter(struct line_parser *lp, struct fttag *fttag);static int parse_def_term(struct line_parser *lp, struct fttag *fttag);static int parse_def_input_filter(struct line_parser *lp, struct fttag *fttag);static int parse_def_output_filter(struct line_parser *lp, struct fttag *fttag);static int parse_def_action(struct line_parser *lp, struct fttag *fttag);static int resolve_actions(struct fttag *fttag); static int walk_free(struct radix_node *rn, struct walkarg *UNUSED);static inline void eval_match_src_as(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_dst_as(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_src_prefix(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_dst_prefix(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_nexthop(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_as(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_prefix(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_tcp_src_port(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_tcp_dst_port(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_tcp_port(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_udp_src_port(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_udp_dst_port(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_udp_port(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_tos(struct fttag_action *fta, struct fts3rec_v1005 *rec);static inline void eval_match_any(struct fttag_action *fta, struct fts3rec_v1005 *rec);#define PARSE_STATE_ACTION 0x1#define PARSE_STATE_DEFINITION 0x2#define NEXT_WORD(A,B)\ for (;;) {\ B = strsep(A, " \t");\ if ((B && *B != 0) || (!B))\ break;\ }\ struct jump { char *name; int state; int (*func)(struct line_parser *lp, struct fttag *fttag);};struct jump pjump[] = {{"tag-action", 0, parse_action}, {"type", PARSE_STATE_ACTION, parse_action_type}, {"match", PARSE_STATE_ACTION, parse_action_match}, {"tag-definition", 0, parse_def}, {"exporter", PARSE_STATE_DEFINITION, parse_def_exporter}, {"term", PARSE_STATE_DEFINITION, parse_def_term}, {"input-filter", PARSE_STATE_DEFINITION, parse_def_input_filter}, {"output-filter", PARSE_STATE_DEFINITION, parse_def_output_filter}, {"action", PARSE_STATE_DEFINITION, parse_def_action}, {0, 0, 0}, };/* * data structures: * * * fttag holds the head pointers to a list of actions, and definitions. * * Each definition holds a list of terms. A term is a combination of * an input filter, output filter and list of actions. * * struct fttag_def : linked list of definitions * struct fttag_action : linked list of actions * struct fttag_def_term : each term in a definition * struct fttag_def_term_actions : each action in a term * * actions contain one of the following: * * struct fttag_prefix_look : prefix radix trie lookup entry * struct fttag_as_look : AS table lookup * struct fttag_port_look : port table lookup * struct fttag_tos_look : tos table lookup * struct fttag_next_hop_look : next hop hash lookup entry * * struct fftag_exp_hash : hash table mapping exporter_ip * to list of definitions. Used * when processing flows. ie, lookup * by exporter, test input/output * filter then use action to add * tags. * *//* * function: fttag_load * * Process fname into fttag. * * tag file format: * * tag-action OSU * # src-prefix|dst-prefix|prefixx * type src-prefi * match 128.146/16 set-src 100 * match 164.107/16 set-src 100 * match 140.254/16 set-src 100 * * tag-action OSU2 * # src-as|dst-as|as * type src-as * match 159 set-src 0x1 * match 600 or-src 0x2 * * tag-action OSU3 * type next-hop * match 199.18.2.2 set-src 100 * match 199.18.2.1 set-src 101 * * tag-definition OSUrouter1 * term * exporter 128.146.1.1 * input-filter 1,2,3,4 * output-filter !5-9 * action OSU * action OSU2 * term * exporter 128.146.2.1 * input-filter 1 * output-filter 5 * * returns: 0 ok * <0 fail */int fttag_load(struct fttag *fttag, char *fname){ static int rn_init_called; struct stat sb; struct jump *jmp; struct line_parser lp; int fd, ret, found; char *buf, *buf2, *c; ret = -1; buf = (char*)0L; bzero(&lp, sizeof lp); bzero(fttag, sizeof *fttag); if (!rn_init_called) { max_keylen = sizeof(struct radix_sockaddr_in); rn_init(); rn_init_called = 1; } FT_SLIST_INIT(&fttag->defs); FT_SLIST_INIT(&fttag->actions); lp.fname = fname; if ((fd = open(fname, O_RDONLY, 0)) < 0) { fterr_warn("open(%s)", fname); goto load_tags_out; } if (fstat(fd, &sb) < 0) { fterr_warn("stat(%s)", fname); goto load_tags_out; } /* allocate storage for file */ if (!(buf = malloc(sb.st_size+1))) { fterr_warn("malloc()"); goto load_tags_out; } /* read in file */ if (read(fd, buf, sb.st_size) != sb.st_size) { fterr_warnx("read(%s): short", fname); goto load_tags_out; } /* null terminate file */ buf[sb.st_size] = 0; buf2 = buf; for (;;) { /* rip a line */ for (;;) { c = strsep(&buf2, "\n"); ++lp.lineno; if ((c && *c != 0) || (!c)) break; } /* no more lines */ if (!c) { goto load_tags_done; } lp.buf = c; /* first word */ NEXT_WORD(&lp.buf, c); /* whitespace only line */ if (!c) { continue; } /* comment line */ if (c && *c == '#') continue; for (jmp = pjump; jmp->name; ++jmp) { found = 0; if (((!jmp->state) || (jmp->state & lp.state)) && (!strcasecmp(c, jmp->name))) { found = 1; if (jmp->func(&lp, fttag)) goto load_tags_out; NEXT_WORD(&lp.buf, c); if (c) { fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c); goto load_tags_out; } break; } } /* test each word */ if (!found) { fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c); goto load_tags_out; } } /* more lines */load_tags_done: if (resolve_actions(fttag)) goto load_tags_out; ret = 0;load_tags_out: if (fd != -1) close(fd); if (buf) free(buf); if (ret == -1) fttag_free(fttag); return ret;} /* fttag_load *//* * function: fttag_defintion_find * * Return a pointer to a fttag_def_lookup for use later with * fttag_def_eval * * Note this allocates storage and precomputes a hash table * to speed up the eval phase. Storage is freed by fttag_free() * * returns : pointer to fttag_def_lookup or null if not found or error. * */struct fttag_def *fttag_def_find(struct fttag *fttag, char *name){ struct fttag_def *ftd; /* foreach definition */ FT_SLIST_FOREACH(ftd, &fttag->defs, chain) { if (!(strcasecmp(ftd->name, name))) return ftd; } return (struct fttag_def*)0L;} /* fttag_def_find *//* * function: parse_action * * process the 'action' line. Each action has a unique name which * is added to the fttag->actions linked list. The current action is * updated in lp. Actions by themself do nothing, they must be pointed * to by a definition. * * returns: 0 ok * <0 fail */int parse_action(struct line_parser *lp, struct fttag *fttag){ char *c; struct fttag_action *fta; NEXT_WORD(&lp->buf, c); if (!c) { fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno); return -1; } /* check if it exists */ FT_SLIST_FOREACH(fta, &fttag->actions, chain) { if (!strcasecmp(c, fta->name)) { fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname, lp->lineno, c); return -1; } } /* no, add a new entry to the list */ if (!(fta = (struct fttag_action*)malloc(sizeof (struct fttag_action)))) { fterr_warn("malloc()"); return -1; } bzero(fta, sizeof *fta); if (!(fta->name = (char*)malloc(strlen(c)+1))) { fterr_warn("malloc()"); free(fta); return -1; } strcpy(fta->name, c); FT_SLIST_INSERT_HEAD(&fttag->actions, fta, chain); lp->state = PARSE_STATE_ACTION; lp->cur_action = fta; return 0;} /* parse_action *//* * function: parse_action_type * * process the 'type' line. When the type is set the initial storage * (table/hash/radix trie) is allocated. * * returns: 0 ok * <0 fail */int parse_action_type(struct line_parser *lp, struct fttag *fttag){ char *c; if (!lp->cur_action) { fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno); return -1; } NEXT_WORD(&lp->buf, c); if (!c) { fterr_warnx("%s line %d: Expecting type.", lp->fname, lp->lineno); return -1; } if (lp->cur_action->type) { fterr_warnx("%s line %d: Type previously defined.", lp->fname, lp->lineno); return -1; } if (!strcasecmp(c, "src-prefix")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_PREFIX; lp->cur_action->eval = eval_match_src_prefix; } else if (!strcasecmp(c, "dst-prefix")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_PREFIX; lp->cur_action->eval = eval_match_dst_prefix; } else if (!strcasecmp(c, "prefix")) { lp->cur_action->eval = eval_match_prefix; lp->cur_action->type = FT_TAG_TYPE_MATCH_PREFIX; } else if (!strcasecmp(c, "next-hop")) { lp->cur_action->eval = eval_match_nexthop; lp->cur_action->type = FT_TAG_TYPE_MATCH_NEXTHOP; } else if (!strcasecmp(c, "src-as")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_AS; lp->cur_action->eval = eval_match_src_as; } else if (!strcasecmp(c, "dst-as")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_AS; lp->cur_action->eval = eval_match_dst_as; } else if (!strcasecmp(c, "as")) { lp->cur_action->eval = eval_match_as; lp->cur_action->type = FT_TAG_TYPE_MATCH_AS; } else if (!strcasecmp(c, "tcp-src-port")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_TCP_PORT; lp->cur_action->eval = eval_match_tcp_src_port; } else if (!strcasecmp(c, "tcp-dst-port")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_TCP_PORT; lp->cur_action->eval = eval_match_tcp_dst_port; } else if (!strcasecmp(c, "tcp-port")) { lp->cur_action->eval = eval_match_tcp_port; lp->cur_action->type = FT_TAG_TYPE_MATCH_TCP_PORT; } else if (!strcasecmp(c, "udp-src-port")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_UDP_PORT; lp->cur_action->eval = eval_match_udp_src_port; } else if (!strcasecmp(c, "udp-dst-port")) { lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_UDP_PORT; lp->cur_action->eval = eval_match_udp_dst_port; } else if (!strcasecmp(c, "udp-port")) { lp->cur_action->eval = eval_match_udp_port; lp->cur_action->type = FT_TAG_TYPE_MATCH_TCP_PORT; } else if (!strcasecmp(c, "tos")) { lp->cur_action->eval = eval_match_tos; lp->cur_action->type = FT_TAG_TYPE_MATCH_TOS; } else if (!strcasecmp(c, "any")) { lp->cur_action->eval = eval_match_any; lp->cur_action->type = FT_TAG_TYPE_MATCH_ANY; } else { fterr_warnx("%s line %d: Unrecognized type.", lp->fname, lp->lineno); return -1; } /* allocate storage for lookup */ if ((lp->cur_action->type & FT_TAG_TYPE_MATCH_AS)) { if (!(lp->cur_action->look = malloc(sizeof (struct fttag_as_look)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->look, sizeof (struct fttag_as_look)); } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_TOS) { if (!(lp->cur_action->look = malloc(sizeof (struct fttag_tos_look)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->look, sizeof (struct fttag_tos_look)); } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_ANY) { if (!(lp->cur_action->look = malloc(sizeof (struct fttag_any_look)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->look, sizeof (struct fttag_any_look)); } else if (lp->cur_action->type & (FT_TAG_TYPE_MATCH_TCP_PORT|FT_TAG_TYPE_MATCH_UDP_PORT)) { if (!(lp->cur_action->look = malloc(sizeof (struct fttag_port_look)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->look, sizeof (struct fttag_port_look)); } else if ((lp->cur_action->type & FT_TAG_TYPE_MATCH_PREFIX)) { if (rn_inithead((void**)&lp->cur_action->look, 32) < 0) { fterr_warnx("rn_inithead(): failed"); return -1; } } else if ((lp->cur_action->type & FT_TAG_TYPE_MATCH_NEXTHOP)) { if (!(lp->cur_action->look = ftchash_new(256, sizeof (struct fttag_next_hop_look), 4, 16))) { fterr_warnx("ftchash_new(): failed");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -