/* * 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: ftxlate.c,v 1.6 2005/05/11 14:03:30 maf Exp $ */ #include "ftconfig.h" #include "ftlib.h" #ifdef HAVE_OPENSSL #define free_func ssl_free_func /* hack, zlib uses free_func also */ #include #include #undef free_func #endif /* HAVE_OPENSSL */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_STRINGS_H #include #endif #if HAVE_STRING_H #include #endif #if !HAVE_STRSEP char *strsep (char **, const char *); #endif struct cryptopan { u_int8_t m_key[16]; /* 128 bit secret key */ u_int8_t m_pad[16]; /* 128 bit secret pad */ #ifdef HAVE_OPENSSL EVP_CIPHER_CTX *cipher_ctx; /* openssl cipher context */ #endif /* HAVE_OPENSSL */ }; static int cryptopan_anon(struct cryptopan *cp, u_int32_t orig_addr, u_int32_t *new_addr); static int cryptopan_free(struct cryptopan *cp); static int cryptopan_init(struct cryptopan *cp, unsigned char *key); static int load_key_file(char *fname, unsigned char *key); struct line_parser { struct ftxlate_action *cur_action; struct ftxlate_def *cur_def; struct ftxlate_def_term *cur_def_term; int state, type; int lineno; char *buf, *fname, *word; }; #define FT_XLATE_TYPE_IP_SRC_ADDR2NET 0x1 #define FT_XLATE_TYPE_IP_DST_ADDR2NET 0x2 #define FT_XLATE_TYPE_IP_SRC_ADDR2CNET 0x3 #define FT_XLATE_TYPE_IP_DST_ADDR2CNET 0x4 #define FT_XLATE_TYPE_IP_ADDR_PRIV_MASK 0x5 #define FT_XLATE_TYPE_TAG_MASK 0x6 #define FT_XLATE_TYPE_SCALE 0x7 #define FT_XLATE_TYPE_SRC_AS 0x8 #define FT_XLATE_TYPE_DST_AS 0x9 #define FT_XLATE_TYPE_IP_PORT_PRIV_MASK 0xA #define FT_XLATE_TYPE_IP_ADDR_ANON 0xB #define FT_XLATE_TYPE_IP_SRC_ADDR_ANON 0xC #define FT_XLATE_TYPE_IP_DST_ADDR_ANON 0xD #define FT_XLATE_FLAG_STOP 0x1 #define FT_XLATE_ALG_CRYPTOPAN_AES128 0x1 struct ftxlate_action { FT_SLIST_ENTRY(ftxlate_action) chain; /* list of all actions */ int type; /* FT_XLATE_TYPE_MATCH_* */ char *name; void *action; void (*eval)(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); u_int64 xfields; }; struct ftxlate_def_term { FT_STAILQ_ENTRY(ftxlate_def_term) chain; /* list of terms */ FT_STAILQ_HEAD(xactdhead, ftxlate_def_term_actions) actions; /* actions */ int type; /* FT_XLATE_TYPE_MATCH_* */ struct ftfil_def *ftfd; /* filter definition */ int flags; u_int64 xfields; }; struct ftxlate_def_term_actions { FT_STAILQ_ENTRY(ftxlate_def_term_actions) chain; /* all actions */ struct ftxlate_action *action; /* filled in by resolve_actions */ char *name; /* temporary, invalid after config file is closed */ }; struct ftxlate_def { FT_SLIST_ENTRY(ftxlate_def) chain; FT_STAILQ_HEAD(xdthead, ftxlate_def_term) terms; /* terms */ char *name; u_int64 xfields; }; struct ftxlate_act_scale { int scale; }; struct ftxlate_act_asn { u_int16 as; }; struct ftxlate_act_tag_mask { u_int32 src_mask; u_int32 dst_mask; }; struct ftxlate_act_ip_addr_priv_mask { u_int32 src_mask; u_int32 dst_mask; }; struct ftxlate_act_ip_port_priv_mask { u_int16 src_mask; u_int16 dst_mask; }; struct ftxlate_act_ip_addr_anon { int init; int algorithm; /* algorithm - cryptopan only for now */ char *key_fname; /* file containing a key, null if not used */ char key[32]; /* key */ time_t key_refresh_next; /* next key refresh */ time_t key_refresh_interval; /* key refresh check rate */ struct cryptopan cp; /* cryptopan context */ }; static int parse_action(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_type(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_mask(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_scale(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_asn(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_algorithm(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_key(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_key_file(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_action_key_refresh(struct line_parser *lp, struct ftxlate *ftxlate); static int decode_hex(char *in, int in_len, unsigned char *out, int out_len); static int parse_def(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_def_term(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_def_filter(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_def_action(struct line_parser *lp, struct ftxlate *ftxlate); static int parse_def_stop(struct line_parser *lp, struct ftxlate *ftxlate); static int resolve_actions(struct ftxlate *ftxlate); static int parse_include_filter(struct line_parser *lp, struct ftxlate *ftxlate); static int load_filters(struct ftxlate *ftxlate); static void eval_ip_src_addr2net(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_dst_addr2net(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_src_addr2cnet(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_dst_addr2cnet(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_addr_privacy_mask(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_port_privacy_mask(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_scale(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_tag_mask(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_src_asn(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_dst_asn(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_src_addr_anon(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_dst_addr_anon(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); static void eval_ip_addr_anon(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo); #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 ftxlate *ftxlate); }; static struct jump pjump[] = { {"include-filter", 0, parse_include_filter}, {"xlate-action", 0, parse_action}, {"type", PARSE_STATE_ACTION, parse_action_type}, {"mask", PARSE_STATE_ACTION, parse_action_mask}, {"scale", PARSE_STATE_ACTION, parse_action_scale}, {"as", PARSE_STATE_ACTION, parse_action_asn}, {"key", PARSE_STATE_ACTION, parse_action_key}, {"key-file", PARSE_STATE_ACTION, parse_action_key_file}, {"key-file-refresh", PARSE_STATE_ACTION, parse_action_key_refresh}, {"algorithm", PARSE_STATE_ACTION, parse_action_algorithm}, {"xlate-definition", 0, parse_def}, {"term", PARSE_STATE_DEFINITION, parse_def_term}, {"filter", PARSE_STATE_DEFINITION, parse_def_filter}, {"stop", PARSE_STATE_DEFINITION, parse_def_stop}, {"action", PARSE_STATE_DEFINITION, parse_def_action}, {0, 0, 0}, }; /* * data structures: * * * ftxlate holds the head pointers to a list of actions, and definitions. * * Each definition holds a list of terms. A term is a combination of * a filter and a list of actions * * struct ftxlate_def : linked list of definitions * struct ftxlate_action : linked list of actions * struct ftxlate_def_term : each term in a definition * struct ftxlate_def_term_actions : each action in a term * * actions contain one of the following: * - note for some actions no additional data is required and action * will be null * * struct ftxlate_act_scale : scale * struct ftxlate_act_tag_mask : source and destination tag mask * struct ftxlate_act_priv_mask : source and destination privacy mask * struct ftxlate_port_priv_mask : source and destination privacy mask * struct ftxlate_act_asn : replacement ASN * * */ /* * function: ftxlate_load * * Process fname into ftxlate. * * returns: 0 ok * <0 fail */ int ftxlate_load(struct ftxlate *ftxlate, struct ftvar *ftvar, char *fname) { struct stat sb; struct jump *jmp; struct line_parser lp; int fd, ret, found; char *buf, *buf2, *c; char sbuf[FT_LP_MAXLINE]; ret = -1; buf = (char*)0L; bzero(&lp, sizeof lp); bzero(ftxlate, sizeof *ftxlate); FT_SLIST_INIT(&ftxlate->defs); FT_SLIST_INIT(&ftxlate->actions); lp.fname = fname; if ((fd = open(fname, O_RDONLY, 0)) < 0) { fterr_warn("open(%s)", fname); goto load_xlate_out; } if (fstat(fd, &sb) < 0) { fterr_warn("stat(%s)", fname); goto load_xlate_out; } /* allocate storage for file */ if (!(buf = malloc(sb.st_size+1))) { fterr_warn("malloc()"); goto load_xlate_out; } /* read in file */ if (read(fd, buf, sb.st_size) != sb.st_size) { fterr_warnx("read(%s): short", fname); goto load_xlate_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_xlate_done; } /* do variable substitutions first */ if (ftvar) { if (ftvar_evalstr(ftvar, c, sbuf, sizeof(sbuf)) < 0) { fterr_warnx("ftvar_evalstr(): failed"); goto load_xlate_done; } } else { strncpy(sbuf, c, sizeof(sbuf)); sbuf[sizeof(sbuf)-1] = 0; } lp.buf = sbuf; /* 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, ftxlate)) goto load_xlate_out; NEXT_WORD(&lp.buf, c); if (c) { fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c); goto load_xlate_out; } break; } } /* test each word */ if (!found) { fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c); goto load_xlate_out; } } /* more lines */ load_xlate_done: if (resolve_actions(ftxlate)) goto load_xlate_out; ret = 0; load_xlate_out: if (fd != -1) close(fd); if (buf) free(buf); if (ret == -1) ftxlate_free(ftxlate); return ret; } /* ftxlate_load */ /* * function: ftxlate_defintion_find * * Return a pointer to a ftxlate_def_actionup for use later with * ftxlate_def_eval * */ struct ftxlate_def *ftxlate_def_find(struct ftxlate *ftxlate, char *name) { struct ftxlate_def *ftx; /* foreach definition */ FT_SLIST_FOREACH(ftx, &ftxlate->defs, chain) { if (!(strcasecmp(ftx->name, name))) return ftx; } return (struct ftxlate_def*)0L; } /* ftxlate_def_find */ /* * function: ftxlate_def_test_xfields * * Check if fields in current flow are valid for a xlate definition -- ie * the definition does not reference a field not contained in the flow. * * returns: 0 okay * 1 fail */ int ftxlate_def_test_xfields(struct ftxlate_def *active_def, u_int64 test) { if ((active_def->xfields & test) != active_def->xfields) return 1; else return 0; } /* ftxlate_def_test_xfields */ /* * function: ftxlate_free * * free resources allocated by ftxlate_load() * */ void ftxlate_free(struct ftxlate *ftxlate) { struct ftxlate_action *ftxa; struct ftxlate_def *ftx; struct ftxlate_def_term *ftxt; struct ftxlate_def_term_actions *ftxta; struct ftxlate_act_ip_addr_anon *ftxiaa; if (ftxlate->ftfil_init) ftfil_free(&ftxlate->ftfil); if (ftxlate->filter_fname) free(ftxlate->filter_fname); /* foreach action, remove the action and associated storge */ while (!FT_SLIST_EMPTY(&ftxlate->actions)) { ftxa = FT_SLIST_FIRST(&ftxlate->actions); FT_SLIST_REMOVE_HEAD(&ftxlate->actions, chain); if (ftxa->action) { /* *_ANON allocated internal resources */ if ((ftxa->type == FT_XLATE_TYPE_IP_ADDR_ANON) || (ftxa->type == FT_XLATE_TYPE_IP_SRC_ADDR_ANON) || (ftxa->type == FT_XLATE_TYPE_IP_DST_ADDR_ANON)) { ftxiaa = ftxa->action; if (ftxiaa->key_fname) free(ftxiaa->key_fname); if (ftxiaa->init) cryptopan_free(&ftxiaa->cp); } /* type *_ANON */ free(ftxa->action); } free(ftxa->name); free(ftxa); } /* while */ /* foreach definition, remove the definition and associated storage */ while (!FT_SLIST_EMPTY(&ftxlate->defs)) { ftx = FT_SLIST_FIRST(&ftxlate->defs); FT_SLIST_REMOVE_HEAD(&ftxlate->defs, chain); /* foreach term in the definition */ while (!FT_STAILQ_EMPTY(&ftx->terms)) { ftxt = FT_STAILQ_FIRST(&ftx->terms); while (!FT_STAILQ_EMPTY(&ftxt->actions)) { ftxta = FT_STAILQ_FIRST(&ftxt->actions); if (ftxta->name) free(ftxta->name); FT_STAILQ_REMOVE_HEAD(&ftxt->actions, chain); free(ftxta); } FT_STAILQ_REMOVE_HEAD(&ftx->terms, chain); free (ftxt); } free(ftx->name); free(ftx); } /* while */ } /* ftxlate_free */ /* * function: ftxlate_def_eval * * perform tag actions on a flow * * run down each term in the definition * evaluate the filter, if okay * run every action * * the filter is activated by * FT_TAG_DEF_FILTER_INPUT - check input * FT_TAG_DEF_FILTER_OUTPUT check output * FT_TAG_DEF_FILTER_EXPORTER check exporter * * * returns 0 */ int ftxlate_def_eval(struct ftxlate_def *ftx, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_def_term *ftxt; struct ftxlate_def_term_actions *ftxta; struct ftxlate_action *ftxa; int fpermit, stop; /* early termination? */ stop = 0; /* foreach term in the definition */ FT_STAILQ_FOREACH(ftxt, &ftx->terms, chain) { /* * if the filter allows this flow then call the xlate evaluation, else * leave it alone. */ /* this filter did not permit an action */ fpermit = 0; if (ftxt->ftfd && ftfil_def_eval(ftxt->ftfd, rec, fo) == FT_FIL_MODE_DENY) continue; else fpermit = 1; /* stop after this term? */ if (fpermit && (ftxt->flags & FT_XLATE_FLAG_STOP)) stop = 1; /* for every action chained to this term */ FT_STAILQ_FOREACH(ftxta, &ftxt->actions, chain) { /* the action */ ftxa = ftxta->action; /* based on the type do the action if a match is made */ ftxa->eval(ftxa, rec, fo); } /* foreach action references by the term */ /* early termination due to stop keyword? */ if (stop) break; } /* foreach term */ return 0; } /* ftxlate_def_eval */ /* * function: parse_action * * process the 'action' line. Each action has a unique name which * is added to the ftxlate->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 ftxlate *ftxlate) { struct ftxlate_action *ftxa; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno); return -1; } /* check if it exists */ FT_SLIST_FOREACH(ftxa, &ftxlate->actions, chain) { if (!strcasecmp(lp->word, ftxa->name)) { fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname, lp->lineno, lp->word); return -1; } } /* no, add a new entry to the list */ if (!(ftxa = (struct ftxlate_action*)malloc(sizeof (struct ftxlate_action)))) { fterr_warn("malloc()"); return -1; } bzero(ftxa, sizeof *ftxa); if (!(ftxa->name = (char*)malloc(strlen(lp->word)+1))) { fterr_warn("malloc()"); free(ftxa); return -1; } strcpy(ftxa->name, lp->word); FT_SLIST_INSERT_HEAD(&ftxlate->actions, ftxa, chain); lp->state = PARSE_STATE_ACTION; lp->cur_action = ftxa; return 0; } /* parse_action */ /* * function: parse_action_type * * process the 'type' line. When the type is set the initial storage * is allocated if necessary. * * returns: 0 ok * <0 fail */ int parse_action_type(struct line_parser *lp, struct ftxlate *ftxlate) { if (!lp->cur_action) { fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno); return -1; } NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { 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(lp->word, "ip-source-address-to-network")) { lp->cur_action->type = FT_XLATE_TYPE_IP_SRC_ADDR2NET; lp->cur_action->eval = eval_ip_src_addr2net; lp->cur_action->xfields |= (FT_XFIELD_SRCADDR|FT_XFIELD_SRC_MASK); } else if (!strcasecmp(lp->word, "ip-destination-address-to-network")) { lp->cur_action->type = FT_XLATE_TYPE_IP_DST_ADDR2NET; lp->cur_action->eval = eval_ip_dst_addr2net; lp->cur_action->xfields |= (FT_XFIELD_DSTADDR|FT_XFIELD_DST_MASK); } else if (!strcasecmp(lp->word, "ip-source-address-to-class-network")) { lp->cur_action->type = FT_XLATE_TYPE_IP_SRC_ADDR2CNET; lp->cur_action->eval = eval_ip_src_addr2cnet; lp->cur_action->xfields |= FT_XFIELD_SRCADDR; } else if (!strcasecmp(lp->word, "ip-destination-address-to-class-network")) { lp->cur_action->type = FT_XLATE_TYPE_IP_DST_ADDR2CNET; lp->cur_action->eval = eval_ip_dst_addr2cnet; lp->cur_action->xfields |= FT_XFIELD_DSTADDR; } else if (!strcasecmp(lp->word, "ip-address-privacy-mask")) { lp->cur_action->type = FT_XLATE_TYPE_IP_ADDR_PRIV_MASK; lp->cur_action->eval = eval_ip_addr_privacy_mask; lp->cur_action->xfields |= (FT_XFIELD_DSTADDR|FT_XFIELD_SRCADDR); } else if (!strcasecmp(lp->word, "ip-port-privacy-mask")) { lp->cur_action->type = FT_XLATE_TYPE_IP_PORT_PRIV_MASK; lp->cur_action->eval = eval_ip_port_privacy_mask; lp->cur_action->xfields |= (FT_XFIELD_DSTPORT|FT_XFIELD_SRCPORT); } else if (!strcasecmp(lp->word, "scale")) { lp->cur_action->type = FT_XLATE_TYPE_SCALE; lp->cur_action->eval = eval_scale; lp->cur_action->xfields |= (FT_XFIELD_DPKTS|FT_XFIELD_DOCTETS); } else if (!strcasecmp(lp->word, "tag-mask")) { lp->cur_action->type = FT_XLATE_TYPE_TAG_MASK; lp->cur_action->eval = eval_tag_mask; lp->cur_action->xfields |= (FT_XFIELD_SRC_TAG|FT_XFIELD_DST_TAG); } else if (!strcasecmp(lp->word, "replace-source-as0")) { lp->cur_action->type = FT_XLATE_TYPE_SRC_AS; lp->cur_action->eval = eval_src_asn; lp->cur_action->xfields |= FT_XFIELD_SRC_AS; } else if (!strcasecmp(lp->word, "replace-destination-as0")) { lp->cur_action->type = FT_XLATE_TYPE_DST_AS; lp->cur_action->eval = eval_dst_asn; lp->cur_action->xfields |= FT_XFIELD_DST_AS; } else if (!strcasecmp(lp->word, "ip-source-address-anonymize")) { lp->cur_action->type = FT_XLATE_TYPE_IP_SRC_ADDR_ANON; lp->cur_action->eval = eval_ip_src_addr_anon; lp->cur_action->xfields |= FT_XFIELD_SRCADDR; } else if (!strcasecmp(lp->word, "ip-destination-address-anonymize")) { lp->cur_action->type = FT_XLATE_TYPE_IP_DST_ADDR_ANON; lp->cur_action->eval = eval_ip_dst_addr_anon; lp->cur_action->xfields |= FT_XFIELD_DSTADDR; } else if (!strcasecmp(lp->word, "ip-address-anonymize")) { lp->cur_action->type = FT_XLATE_TYPE_IP_ADDR_ANON; lp->cur_action->eval = eval_ip_addr_anon; lp->cur_action->xfields |= (FT_XFIELD_SRCADDR|FT_XFIELD_DSTADDR); } else { fterr_warnx("%s line %d: Unrecognized type.", lp->fname, lp->lineno); return -1; } /* allocate storage for action if required */ if ((lp->cur_action->type == FT_XLATE_TYPE_IP_ADDR_PRIV_MASK)) { if (!(lp->cur_action->action = malloc(sizeof (struct ftxlate_act_ip_addr_priv_mask)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->action, sizeof (struct ftxlate_act_ip_addr_priv_mask)); } else if ((lp->cur_action->type == FT_XLATE_TYPE_IP_PORT_PRIV_MASK)) { if (!(lp->cur_action->action = malloc(sizeof (struct ftxlate_act_ip_port_priv_mask)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->action, sizeof (struct ftxlate_act_ip_port_priv_mask)); } else if (lp->cur_action->type == FT_XLATE_TYPE_TAG_MASK) { if (!(lp->cur_action->action = malloc(sizeof (struct ftxlate_act_tag_mask)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->action, sizeof (struct ftxlate_act_tag_mask)); } else if (lp->cur_action->type == FT_XLATE_TYPE_SCALE) { if (!(lp->cur_action->action = malloc(sizeof (struct ftxlate_act_scale)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->action, sizeof (struct ftxlate_act_scale)); } else if ((lp->cur_action->type == FT_XLATE_TYPE_SRC_AS) || (lp->cur_action->type == FT_XLATE_TYPE_DST_AS)) { if (!(lp->cur_action->action = malloc(sizeof (struct ftxlate_act_asn)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->action, sizeof (struct ftxlate_act_asn)); } else if ((lp->cur_action->type == FT_XLATE_TYPE_IP_SRC_ADDR_ANON) || (lp->cur_action->type == FT_XLATE_TYPE_IP_ADDR_ANON) || (lp->cur_action->type == FT_XLATE_TYPE_IP_DST_ADDR_ANON)) { if (!(lp->cur_action->action = malloc(sizeof (struct ftxlate_act_ip_addr_anon)))) { fterr_warn("malloc()"); return -1; } bzero(lp->cur_action->action, sizeof (struct ftxlate_act_ip_addr_anon)); } return 0; } /* parse_action_type */ /* * function: parse_action_mask * * process the 'mask' line in an action. Handles the tag-mask * ip-address-privacy-mask and port-number-privacy-mask actions. * * returns: 0 ok * <0 fail */ int parse_action_mask(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_act_tag_mask *ftxatm; struct ftxlate_act_ip_addr_priv_mask *ftxaiapm; struct ftxlate_act_ip_port_priv_mask *ftxaippm; u_int32 src_mask, dst_mask; char *src_maskc, *dst_maskc; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } if ((lp->cur_action->type != FT_XLATE_TYPE_IP_ADDR_PRIV_MASK) && (lp->cur_action->type != FT_XLATE_TYPE_TAG_MASK) && (lp->cur_action->type != FT_XLATE_TYPE_IP_PORT_PRIV_MASK)) { fterr_warnx("%s line %d: Illegal keyword.", lp->fname, lp->lineno); return -1; } ftxatm = lp->cur_action->action; ftxaiapm = lp->cur_action->action; ftxaippm = lp->cur_action->action; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting source mask.", lp->fname, lp->lineno); return -1; } src_maskc = lp->word; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting destination mask.", lp->fname, lp->lineno); return -1; } dst_maskc = lp->word; src_mask = strtoull(src_maskc, (char**)0L, 0); dst_mask = strtoull(dst_maskc, (char**)0L, 0); if (lp->cur_action->type == FT_XLATE_TYPE_TAG_MASK) { ftxatm->src_mask = src_mask; ftxatm->dst_mask = dst_mask; } else if (lp->cur_action->type == FT_XLATE_TYPE_IP_ADDR_PRIV_MASK) { ftxaiapm->src_mask = src_mask; ftxaiapm->dst_mask = dst_mask; } else if (lp->cur_action->type == FT_XLATE_TYPE_IP_PORT_PRIV_MASK) { ftxaippm->src_mask = src_mask; ftxaippm->dst_mask = dst_mask; } else { fterr_errx(1, "parse_action_match(): internal error"); } return 0; } /* parse_action_mask */ /* * function: parse_action_scale * * process the 'scale' line in an action. * * returns: 0 ok * <0 fail */ int parse_action_scale(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_act_scale *ftxs; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } if (lp->cur_action->type != FT_XLATE_TYPE_SCALE) { fterr_warnx("%s line %d: Illegal keyword.", lp->fname, lp->lineno); return -1; } ftxs = lp->cur_action->action; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting scale.", lp->fname, lp->lineno); return -1; } ftxs->scale = atoi(lp->word); return 0; } /* parse_action_scale */ /* * function: parse_action_asn * * process the 'as' line in an action. * * returns: 0 ok * <0 fail */ int parse_action_asn(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_act_asn *ftxasn; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } if ((lp->cur_action->type != FT_XLATE_TYPE_SRC_AS) && (lp->cur_action->type != FT_XLATE_TYPE_DST_AS)) { fterr_warnx("%s line %d: Illegal keyword.", lp->fname, lp->lineno); return -1; } ftxasn = lp->cur_action->action; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting AS.", lp->fname, lp->lineno); return -1; } ftxasn->as = atoi(lp->word); return 0; } /* parse_action_asn */ /* * function: parse_action_key * * process the 'key' line in an action. * * returns: 0 ok * <0 fail */ int parse_action_key(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_act_ip_addr_anon *ftxiaa; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } if ((lp->cur_action->type != FT_XLATE_TYPE_IP_ADDR_ANON) && (lp->cur_action->type != FT_XLATE_TYPE_IP_SRC_ADDR_ANON) && (lp->cur_action->type != FT_XLATE_TYPE_IP_DST_ADDR_ANON)) { fterr_warnx("%s line %d: Illegal keyword.", lp->fname, lp->lineno); return -1; } ftxiaa = lp->cur_action->action; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting Key.", lp->fname, lp->lineno); return -1; } if (decode_hex(lp->word, 64, ftxiaa->key, 32) < 0) { fterr_warnx("%s line %d: decode_hex() failed.", lp->fname, lp->lineno); return -1; } return 0; } /* parse_action_key */ /* * function: parse_action_key_file * * process the 'key-file' line in an action. * * returns: 0 ok * <0 fail */ int parse_action_key_file(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_act_ip_addr_anon *ftxiaa; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } ftxiaa = lp->cur_action->action; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting key-file.", lp->fname, lp->lineno); return -1; } if (!(ftxiaa->key_fname = (char*)malloc(strlen(lp->word)+1))) { fterr_warn("malloc()"); return -1; } strcpy(ftxiaa->key_fname, lp->word); if (load_key_file(ftxiaa->key_fname, (char*)&ftxiaa->key) < 0) { fterr_warnx("Failed to load key from %s.", ftxiaa->key_fname); } return 0; } /* parse_action_key_file */ /* * function: parse_action_algorithm * * process the 'algorithm' line in an action. * * returns: 0 ok * <0 fail */ int parse_action_algorithm(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_act_ip_addr_anon *ftxiaa; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } ftxiaa = lp->cur_action->action; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting algorithm.", lp->fname, lp->lineno); return -1; } #ifdef HAVE_OPENSSL if (strcasecmp(lp->word, "cryptopan-aes128")) { fterr_warnx("%s line %d: Expecting CryptoPAn-aes128", lp->fname, lp->lineno); return -1; } #else fterr_warnx("%s line %d: OpenSSL not compiled in.", lp->fname, lp->lineno); return -1; #endif /* HAVE_OPENSSL */ ftxiaa->algorithm = FT_XLATE_ALG_CRYPTOPAN_AES128; return 0; } /* parse_action_algorithm */ /* * function: parse_action_key_refresh * * process the 'key-refresh' line in an action. * * returns: 0 ok * <0 fail */ int parse_action_key_refresh(struct line_parser *lp, struct ftxlate *ftxlate) { time_t now, t1; struct tm *tm; struct ftxlate_act_ip_addr_anon *ftxiaa; char *c; int hour, min, sec, interval; if (!lp->cur_action->type) { fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno); return -1; } ftxiaa = lp->cur_action->action; /* key-refresh interval start-time */ NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting interval.", lp->fname, lp->lineno); return -1; } interval = ftxiaa->key_refresh_interval = atoi(lp->word); NEXT_WORD(&lp->buf, lp->word); /* parse out time */ hour = min = sec = 0; if (!(c = strsep(&lp->word, ":"))) goto done; hour = atoi(c); if (!(c = strsep(&lp->word, ":"))) goto done; min = atoi(c); if (!(c = strsep(&lp->word, ":"))) goto done; sec = atoi(c); if (lp->word) { fterr_warnx("%s line %d: Unexpected text: %s", lp->fname, lp->lineno, lp->word); return -1; } done: now = time((time_t)0L); tm = localtime(&now); /* calculate start time based on user input? */ if (hour|min|sec) { tm->tm_hour = hour; tm->tm_min = min; tm->tm_sec = sec; t1 = mktime(tm); /* start time is always in the future */ if (t1 < now) t1 += 86400; /* else it's on next interval minutes */ } else { tm->tm_min = (tm->tm_min / interval)*interval + interval; tm->tm_sec = 0; if (tm->tm_min >= 60) tm->tm_min -= 60; t1 = mktime(tm); /* start time is always in the future */ if (t1 < now) t1 += 3600; /* minute rollover */ } ftxiaa->key_refresh_next = t1; fterr_info("cryptopan key refresh at %lu.", ftxiaa->key_refresh_next); return 0; } /* parse_action_key_refresh */ /* * function: parse_def * * process the 'definition' line. Each definition has a unique name which * is added to the ftxlate->defs linked list. The current definition is * updated in lp. * * returns: 0 ok * <0 fail */ int parse_def(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_def *ftx; NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno); return -1; } /* check if it exists */ FT_SLIST_FOREACH(ftx, &ftxlate->defs, chain) { if (!strcasecmp(lp->word, ftx->name)) { fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname, lp->lineno, lp->word); return -1; } } /* no, add a new entry to the list */ if (!(ftx = (struct ftxlate_def*)malloc(sizeof (struct ftxlate_def)))) { fterr_warn("malloc()"); return -1; } bzero(ftx, sizeof *ftx); FT_STAILQ_INIT(&ftx->terms); if (!(ftx->name = (char*)malloc(strlen(lp->word)+1))) { fterr_warn("malloc()"); free(ftx); return -1; } strcpy(ftx->name, lp->word); FT_SLIST_INSERT_HEAD(&ftxlate->defs, ftx, chain); lp->state = PARSE_STATE_DEFINITION; lp->cur_def = ftx; lp->cur_def_term = ( struct ftxlate_def_term*)0L; return 0; } /* parse_def */ /* * function: parse_def_term * * process the term line. Each definition has a list of terms, the * terms have a common input, output, and exporter IP filter and * may have one or more actions. Without an action a term has * no purpose. * * returns: 0 ok * <0 fail */ int parse_def_term(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_def_term *ftxt; if (!lp->cur_def) { fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno); return -1; } /* no, add a new term entry to this definition */ if (!(ftxt = (struct ftxlate_def_term*)malloc(sizeof *ftxt))) { fterr_warn("malloc()"); return -1; } bzero(ftxt, sizeof *ftxt); FT_STAILQ_INIT(&ftxt->actions); FT_STAILQ_INSERT_TAIL(&lp->cur_def->terms, ftxt, chain); lp->cur_def_term = ftxt; return 0; } /* parse_def_term */ /* * function: parse_def_stop * * process the stop line. When the filter for this term matches * and a 'stop' is defined no further actions are performed. * * returns: 0 ok * <0 fail */ int parse_def_stop(struct line_parser *lp, struct ftxlate *ftxlate) { if (!lp->cur_def_term) { fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno); return -1; } lp->cur_def_term->flags |= FT_XLATE_FLAG_STOP; return 0; } /* parse_def_term */ /* * function: parse_def_filter * * process the 'filter' line. * * returns: 0 ok * <0 fail */ int parse_def_filter(struct line_parser *lp, struct ftxlate *ftxlate) { if (!lp->cur_def_term) { fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno); return -1; } NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting filter name.", lp->fname, lp->lineno); return -1; } if (lp->cur_def_term->ftfd) { fterr_warnx("%s line %d: Filter previously defined for term.", lp->fname, lp->lineno); return -1; } /* delay loading the filters until one is requested */ if (load_filters(ftxlate)) { fterr_warnx("%s line %d: Filters not loaded.", lp->fname, lp->lineno); return -1; } if (!(lp->cur_def_term->ftfd = ftfil_def_find(&ftxlate->ftfil, lp->word))) { fterr_warnx("%s line %d: Filter definition not found.", lp->fname, lp->lineno); return -1; } /* any fields referenced in the filter are now required for the xlate */ lp->cur_def->xfields |= lp->cur_def_term->ftfd->xfields; return 0; } /* parse_def_filter */ /* * function: parse_def_action * * foreach action listed, add it to a linked list of actions for the * definition. Note resolve_actions() must be called before the actions * are valid. * * returns: 0 ok * <0 fail */ int parse_def_action(struct line_parser *lp, struct ftxlate *ftxlate) { struct ftxlate_def_term_actions *ftxta; if (!lp->cur_def_term) { fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno); return -1; } NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting action.", lp->fname, lp->lineno); return -1; } /* add a new entry to the list */ if (!(ftxta = (struct ftxlate_def_term_actions*)malloc(sizeof *ftxta))) { fterr_warn("malloc()"); return -1; } bzero(ftxta, sizeof *ftxta); if (!(ftxta->name = (char*)malloc(strlen(lp->word)+1))) { fterr_warn("malloc()"); free(ftxta); return -1; } strcpy(ftxta->name, lp->word); FT_STAILQ_INSERT_TAIL(&lp->cur_def_term->actions, ftxta, chain); /* resolve the ftxta->action later in resolve_actions */ return 0; } /* parse_def_action */ /* * function: parse_include_filter * * process the 'include-filter' line. Allow the default filter location * to be changed. * * returns: 0 ok * <0 fail */ int parse_include_filter(struct line_parser *lp, struct ftxlate *ftxlate) { NEXT_WORD(&lp->buf, lp->word); if (!lp->word) { fterr_warnx("%s line %d: Expecting pathname.", lp->fname, lp->lineno); return -1; } if (ftxlate->filter_fname) { fterr_warnx("%s line %d: Filter pathname previously specified.", lp->fname, lp->lineno); return -1; } if (!(ftxlate->filter_fname = (char*)malloc(strlen(lp->word)+1))) { fterr_warn("malloc()"); return -1; } strcpy(ftxlate->filter_fname, lp->word); return 0; } /* parse_include_filter */ /* * function: resolve_actions * * The parser points to the name of the action in the definition to allow * for definitions to be defined before actions in the config file. This * fixes the pointers so the definitions point to the actions * * returns: 0 ok * <0 fail (an action could not be resolved) */ int resolve_actions(struct ftxlate *ftxlate) { struct ftxlate_def *ftx; struct ftxlate_def_term *ftxt; struct ftxlate_def_term_actions *ftxta; struct ftxlate_action *ftxa; struct ftxlate_act_ip_addr_anon *ftxiaa; int i, found; /* foreach action do any additional initialization */ FT_SLIST_FOREACH(ftxa, &ftxlate->actions, chain) { /* *_ANON types need some extra work */ if ((ftxa->type == FT_XLATE_TYPE_IP_ADDR_ANON) || (ftxa->type == FT_XLATE_TYPE_IP_SRC_ADDR_ANON) || (ftxa->type == FT_XLATE_TYPE_IP_DST_ADDR_ANON)) { ftxiaa = ftxa->action; /* only supported alg is cryptopan-eas128 */ if (ftxiaa->algorithm != FT_XLATE_ALG_CRYPTOPAN_AES128) { fterr_warnx("Action %s: unknown anonymization algorithm", ftxa->name); return -1; } /* check for key of all 0's */ found = 0; for (i = 0; i < 32; ++i) if (ftxiaa->key[i] != 0) found = 1; if (found == 0) { fterr_warnx("Action %s: uninitialized key.", ftxa->name); return -1; } /* initialize cryptopan */ if (cryptopan_init(&ftxiaa->cp, ftxiaa->key) < 0) { fterr_warnx("Action %s: cryptopan_init() failed.", ftxa->name); return -1; } ftxiaa->init = 1; } /* *_ANON work */ } /* foreach definition */ FT_SLIST_FOREACH(ftx, &ftxlate->defs, chain) { /* foreach term in the definition */ FT_STAILQ_FOREACH(ftxt, &ftx->terms, chain) { /* foreach action in the term */ FT_STAILQ_FOREACH(ftxta, &ftxt->actions, chain) { found = 0; /* foreach action */ FT_SLIST_FOREACH(ftxa, &ftxlate->actions, chain) { if (!(strcasecmp(ftxa->name, ftxta->name))) { ftxta->action = ftxa; ftx->xfields |= ftxa->xfields; found = 1; break; } } } if (!found) { fterr_warnx("Unable to resolve action \"%s\" in xlate-definition \"%s\".", ftxta->name, ftx->name); return -1; } } } return 0; } /* resolve actions */ static void eval_ip_src_addr2net(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct fts3rec_all2 cur; FT_RECGET_SRC_MASK(cur,rec,*fo); *((u_int32*)(rec+(*fo).srcaddr)) &= ipv4_len2mask(cur.src_mask); } /* eval_ip_src_addr2net */ static void eval_ip_dst_addr2net(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct fts3rec_all2 cur; FT_RECGET_DST_MASK(cur,rec,*fo); *((u_int32*)(rec+(*fo).dstaddr)) &= ipv4_len2mask(cur.dst_mask); } /* eval_ip_dst_addr2net */ static void eval_ip_src_addr2cnet(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct fts3rec_all2 cur; FT_RECGET_SRCADDR(cur,rec,*fo); if ((cur.srcaddr & 0x80000000) == 0) *((u_int32*)(rec+(*fo).srcaddr)) &= 0xFF000000; else if ((cur.srcaddr & 0xC0000000) == 0x80000000) *((u_int32*)(rec+(*fo).srcaddr)) &= 0xFFFF0000; else if ((cur.srcaddr & 0xC0000000) == 0xC0000000) *((u_int32*)(rec+(*fo).srcaddr)) &= 0xFFFFFF00; } /* eval_ip_src_addr2cnet */ static void eval_ip_dst_addr2cnet(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct fts3rec_all2 cur; FT_RECGET_DSTADDR(cur,rec,*fo); if ((cur.dstaddr & 0x80000000) == 0) *((u_int32*)(rec+(*fo).dstaddr)) &= 0xFF000000; else if ((cur.dstaddr & 0xC0000000) == 0x80000000) *((u_int32*)(rec+(*fo).dstaddr)) &= 0xFFFF0000; else if ((cur.dstaddr & 0xC0000000) == 0xC0000000) *((u_int32*)(rec+(*fo).dstaddr)) &= 0xFFFFFF00; } /* eval_ip_dst_addr2cnet */ static void eval_ip_addr_privacy_mask(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_ip_addr_priv_mask *ftxiapm; ftxiapm = ftxa->action; *((u_int32*)(rec+(*fo).srcaddr)) &= ftxiapm->src_mask; *((u_int32*)(rec+(*fo).dstaddr)) &= ftxiapm->dst_mask; } /* eval_ip_addr_privacy_mask */ static void eval_ip_port_privacy_mask(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_ip_port_priv_mask *ftxaipm; ftxaipm = ftxa->action; *((u_int16*)(rec+(*fo).srcport)) &= ftxaipm->src_mask; *((u_int16*)(rec+(*fo).dstport)) &= ftxaipm->dst_mask; } /* eval_ip_port_privacy_mask */ static void eval_tag_mask(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_tag_mask *ftxatm; ftxatm = ftxa->action; *((u_int32*)(rec+(*fo).src_tag)) &= ftxatm->src_mask; *((u_int32*)(rec+(*fo).dst_tag)) &= ftxatm->dst_mask; } /* eval_tag_mask */ static void eval_scale(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_scale *ftxs; ftxs = ftxa->action; *((u_int32*)(rec+(*fo).dOctets)) *= ftxs->scale; *((u_int32*)(rec+(*fo).dPkts)) *= ftxs->scale; } /* eval_scale */ static void eval_src_asn(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_asn *ftxasn; if (*((u_int16*)(rec+(*fo).src_as)) == 0) { ftxasn = ftxa->action; *((u_int16*)(rec+(*fo).src_as)) = ftxasn->as; } } /* eval_src_asn */ static void eval_dst_asn(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_asn *ftxasn; if (*((u_int16*)(rec+(*fo).dst_as)) == 0) { ftxasn = ftxa->action; *((u_int16*)(rec+(*fo).dst_as)) = ftxasn->as; } } /* eval_dst_asn */ static void eval_ip_src_addr_anon(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_ip_addr_anon *ftxiaa; u_int32 new; time_t now; ftxiaa = ftxa->action; /* if key_refresh_next is set check for key to be loaded */ if (ftxiaa->key_refresh_next) { now = time((time_t)0L); if (now > ftxiaa->key_refresh_next) { /* get next interval, handle skipped intervals (no flows to trigger) */ while (now > ftxiaa->key_refresh_next) ftxiaa->key_refresh_next += ftxiaa->key_refresh_interval*60; /* * load new key and re-init cryptopan. If key load fails continue * using existing key */ if (load_key_file(ftxiaa->key_fname, (char*)&ftxiaa->key) < 0) { fterr_warnx("Failed to load key from %s.", ftxiaa->key_fname); } else { fterr_info("cryptopan key reload from %s successful. Next refresh at %lu.", ftxiaa->key_fname, ftxiaa->key_refresh_next); cryptopan_free(&ftxiaa->cp); if (cryptopan_init(&ftxiaa->cp, ftxiaa->key) < 0) fterr_warnx("cryptopan_init(): failed."); } } } /* refresh key? */ if (cryptopan_anon(&ftxiaa->cp, *((u_int32*)(rec+(*fo).srcaddr)), &new) < 0) { fterr_errx(1, "cryptopan_anon(): failed"); } *((u_int32*)(rec+(*fo).srcaddr)) = new; } /* eval_ip_src_addr_anon */ static void eval_ip_dst_addr_anon(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { struct ftxlate_act_ip_addr_anon *ftxiaa; u_int32 new; time_t now; ftxiaa = ftxa->action; /* if key_refresh_next is set check for key to be loaded */ if (ftxiaa->key_refresh_next) { now = time((time_t)0L); if (now > ftxiaa->key_refresh_next) { /* get next interval, handle skipped intervals (no flows to trigger) */ while (now > ftxiaa->key_refresh_next) ftxiaa->key_refresh_next += ftxiaa->key_refresh_interval*60; /* * load new key and re-init cryptopan. If key load fails continue * using existing key */ if (load_key_file(ftxiaa->key_fname, (char*)&ftxiaa->key) < 0) { fterr_warnx("Failed to load key from %s.", ftxiaa->key_fname); } else { fterr_info("cryptopan key reload from %s successful. Next refresh at %lu.", ftxiaa->key_fname, ftxiaa->key_refresh_next); cryptopan_free(&ftxiaa->cp); if (cryptopan_init(&ftxiaa->cp, ftxiaa->key) < 0) fterr_warnx("cryptopan_init(): failed."); } } } /* refresh key? */ if (cryptopan_anon(&ftxiaa->cp, *((u_int32*)(rec+(*fo).dstaddr)), &new) < 0) { fterr_errx(1, "cryptopan_anon(): failed"); } *((u_int32*)(rec+(*fo).dstaddr)) = new; } /* eval_ip_dst_addr_anon */ static void eval_ip_addr_anon(struct ftxlate_action *ftxa, char *rec, struct fts3rec_offsets *fo) { eval_ip_src_addr_anon(ftxa, rec, fo); eval_ip_dst_addr_anon(ftxa, rec, fo); } /* eval_ip_addr_anon */ /* * function: load_filters * * load the filter definitions if they have not been loaded * * return value of ftfil_load() * */ static int load_filters(struct ftxlate *ftxlate) { /* work to do? */ if (ftxlate->ftfil_init) return 0; if (ftfil_load(&ftxlate->ftfil, ftxlate->ftvar, (ftxlate->filter_fname) ? ftxlate->filter_fname : FT_PATH_CFG_FILTER)) { return 1; } ftxlate->ftfil_init = 1; return 0; } /* load_filters */ /* * function: load_key_file * * load 32 byte hex key from fname * * returns: 0 okay * -1 fail */ static int load_key_file(char *fname, unsigned char *key) { struct stat sb; int fd, ret; char *buf; buf = (char*)0L; ret = -1; if ((fd = open(fname, O_RDONLY, 0)) < 0) { fterr_warn("open(%s)", fname); goto load_key_file_out; } if (fstat(fd, &sb) < 0) { fterr_warn("stat(%s)", fname); goto load_key_file_out; } /* allocate storage for file */ if (!(buf = malloc(sb.st_size+1))) { fterr_warn("malloc()"); goto load_key_file_out; } /* read in file */ if (read(fd, buf, sb.st_size) != sb.st_size) { fterr_warnx("read(%s): short", fname); goto load_key_file_out; } /* null terminate file */ buf[sb.st_size] = 0; /* only using 64 hex digits */ if (sb.st_size > 64) buf[64] = 0; if (decode_hex(buf, 64, key, 32) < 0) { fterr_warnx("decode_hex(): failed for %s.", fname); goto load_key_file_out; } ret = 0; /* good */ load_key_file_out: if (fd != -1) close(fd); if (buf) free(buf); return ret; } /* load_key_file */ /* * function: decode_hex() * * decode max of in_len bytes from in as hex, store result in out. * out is out_len bytes * * in - null terminated character string to decode. * in_len - max hex digits to decode (may be > strlen(in) * out - decoded bits * out_len - length of out buffer * * return -1 - error (non hex digit encountered) * 0 - successful decode * */ static int decode_hex(char *in, int in_len, unsigned char *out, int out_len) { int i, l; unsigned char v, odd; bzero(out, out_len); l = strlen(in); odd = 0; out += out_len-1; if (l > in_len) return -1; in += l-1; for (i = 0; i < l; ++i) { if (*in >= '0' && *in <= '9') v = *in - '0'; else if (*in >= 'a' && *in <= 'f') v = *in - 'a' + 10; else if (*in >= 'A' && *in <= 'F') v = *in - 'A' + 10; else return -1; if (!odd) { *out |= v; } else { *out |= v<<4; --out; } --in; odd = odd ? 0 : 1; } return 0; } /* decode_hex */ /* * cryptopan_* code closely based on Crypto-PAn.1.0 by Jinliang Fan * * Crypto-PAn copyright: * * Name of Software: Crypto-PAn, hereafter (Software) * * Copyright 2002 * Georgia Tech Research Corporation * Atlanta, Georgia 30332. * All Rights Reserved * * The following Software is posted on the Internet by the Georgia * Tech Research Corporation (GTRC). It was developed by employees * of the Georgia Institute of Technology in the College of Computing. * GTRC hereby grants to the user a non-exclusive, royalty-free * license to utilize such Software for the User's own purposes * pursuant to the following conditions. * * * THE SOFTWARE IS LICENSED ON AN "AS IS" BASIS. GTRC MAKES NO WARRANTY * THAT ALL ERRORS CAN BE OR HAVE BEEN ELIMINATED FROM THE SOFTWARE. * GTRC SHALL NOT BE RESPONSIBLE FOR LOSSES OF ANY KIND RESULTING FROM * THE USE OF THE SOFTWARE AND ITS ACCOMPANYING DOCUMENTATION, AND CAN * IN NO WAY PROVIDE COMPENSATION FOR ANY LOSSES SUSTAINED, INCLUDING * BUT NOT LIMITED TO ANY OBLIGATION, LIABILITY, RIGHT, CLAIM OR REMEDY * FOR TORT, OF FOR ANY ACTUAL OR ALLEGED INFRINGEMENT OF PATENTS, COPYRIGHTS, * TRADE SECRETS, OR SIMILAR RIGHTS OF THIRD PARTIES, NOR ANY BUSINESS * EXPENSE, MACHINE DOWNTIME, OR DAMAGES CAUSED LICENSEE BY ANY DEFICIENCY, * DEFECT OR ERROR IN THE SOFTWARE OR MALFUNCTION THEREOF, NOR ANY * INCIDENTAL OR CONSEQUENTIAL DAMAGES, HOWEVER CAUSED. GTRC DISCLAIMS * ALL WARRANTIES, BOTH EXPRESS AND IMPLIED RESPECTING THE USE AND * OPERATION OF THE SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * PARTICULAR PURPOSE AND ANY IMPLIED WARRANTY ARISING FROM COURSE * OF PERFORMANCE, COURSE OF DEALING OR USAGE OF TRADE. GTRC MAKES NO * WARRANTY THAT THE SOFTWARE IS ADEQUATELY OR COMPLETELY DESCRIBED * IN, OR BEHAVES IN ACCORDANCE WITH ANY OF THE ACCOMPANYING * DOCUMENTATION. THE USER OF THE SOFTWARE IS EXPECTED TO MAKE THE FINAL * EVALUATION OF THE SOFTWARE'S USEFULNESS IN USER'S OWN ENVIRONMENT. * */ /* * function: cryptopan_init * * Initializes cryptopan structure. cryptopan_free() must be called * to deallocate resources * * returns: 0 okay * -1 fail */ static int cryptopan_init(struct cryptopan *cp, unsigned char *key) { #ifdef HAVE_OPENSSL int i; /* clear */ bzero(cp, sizeof *cp); /* copy in key */ bcopy(key, cp->m_key, 16); /* init crypto */ if (!(cp->cipher_ctx = (EVP_CIPHER_CTX*) malloc(sizeof(EVP_CIPHER_CTX)))) { return -1; } EVP_CIPHER_CTX_init(cp->cipher_ctx); /* disable padding */ if (!(EVP_CIPHER_CTX_set_padding(cp->cipher_ctx, 0))) { cryptopan_free(cp); return -1; } /* init encryption */ if (!(EVP_EncryptInit(cp->cipher_ctx, EVP_aes_128_ecb(), key, NULL))) { cryptopan_free(cp); return -1; } /* set pad */ i = 16; if (!(EVP_EncryptUpdate(cp->cipher_ctx, cp->m_pad, &i, key+16, i))) { cryptopan_free(cp); return -1; } #endif /* HAVE_OPENSSL */ return 0; } /* cryptopan_init */ /* * function: cryptopan_free * * Frees resources allocated by cryptopan_init() * * returns: 0 okay * -1 fail */ static int cryptopan_free(struct cryptopan *cp) { #ifdef HAVE_OPENSSL EVP_CIPHER_CTX_cleanup(cp->cipher_ctx); if (cp->cipher_ctx) free (cp->cipher_ctx); #endif /* HAVE_OPENSSL */ return 0; } /* cryptopan_free */ /* * function: cryptopan_free * * Anonymize orig_addr, storing result in new_addr * see - http://www.cc.gatech.edu/computing/Telecomm/cryptopan/ * * returns: 0 okay * -1 fail */ static int cryptopan_anon(struct cryptopan *cp, u_int32_t orig_addr, u_int32_t *new_addr) { u_int8_t rin_output[16]; u_int8_t rin_input[16]; u_int8_t *m_pad; u_int32_t result, first4bytes_pad, first4bytes_input; int i, pos; result = 0; m_pad = cp->m_pad; bcopy(m_pad, rin_input, 16); first4bytes_pad = (((u_int32_t) m_pad[0]) << 24) + (((u_int32_t) m_pad[1]) << 16) + (((u_int32_t) m_pad[2]) << 8) + (u_int32_t) m_pad[3]; /* * For each prefixes with length from 0 to 31, generate a bit using the * Rijndael cipher, which is used as a pseudorandom function here. The * bits generated in every rounds are combineed into a pseudorandom * one-time-pad. */ for (pos = 0; pos <= 31 ; pos++) { /* * Padding: The most significant pos bits are taken from orig_addr. * The other 128-pos bits are taken from m_pad. The variables * first4bytes_pad and first4bytes_input are used to handle the * annoying byte order problem. */ if (pos == 0) first4bytes_input = first4bytes_pad; else first4bytes_input = ((orig_addr >> (32-pos)) << (32-pos)) | ((first4bytes_pad<> pos); rin_input[0] = (u_int8_t) (first4bytes_input >> 24); rin_input[1] = (u_int8_t) ((first4bytes_input << 8) >> 24); rin_input[2] = (u_int8_t) ((first4bytes_input << 16) >> 24); rin_input[3] = (u_int8_t) ((first4bytes_input << 24) >> 24); /* * Encryption: The Rijndael cipher is used as pseudorandom function. * During each round, only the first bit of rin_output is used. */ i = 16; #ifdef HAVE_OPENSSL if (!(EVP_EncryptUpdate(cp->cipher_ctx, rin_output, &i, rin_input, i))) { cryptopan_free(cp); return -1; } #endif /* HAVE_OPENSSL */ /* Combination: the bits are combined into a pseudorandom one-time-pad */ result |= (rin_output[0] >> 7) << (31-pos); } /* XOR the orginal address with the pseudorandom one-time-pad */ *new_addr = result ^ orig_addr; return 0; } /* cryptopan_anon */