I rewrite flow-merge.c to extend it with easy flow filter (switch -f).
Filter have flexible and simple syntax:
start : sp
| sp cond sp
;
cond : expr
| cond spaces expr
| cond sp '|' '|' sp expr
;
expr : 'p' 'r' 'o' 't' 'o' spaces protos
| 'i' 'p' spaces ipnets
| 's' 'r' 'c' '-' 'i' 'p' spaces ipnets
| 'd' 's' 't' '-' 'i' 'p' spaces ipnets
| 'p' 'o' 'r' 't' spaces ports
| 's' 'r' 'c' '-' 'p' 'o' 'r' 't' spaces ports
| 'd' 's' 't' '-' 'p' 'o' 'r' 't' spaces ports
| '!' sp expr
| '(' sp cond sp ')'
;
protos : proto
| '{' sp listprotos sp '}'
;
listprotos : proto
| listprotos sp ',' sp proto
;
proto : 'i' 'p'
| 'i' 'c' 'm' 'p'
| 't' 'c' 'p'
| 'u' 'd' 'p'
| 'i' 'p' 'e' 'n' 'c' 'a' 'p'
| 'g' 'r' 'e'
| '*'
| number
| '!' proto
;
ipnets : ipnet
| '{' sp listipnets sp '}'
;
listipnets : ipnet
| listipnets sp ',' sp ipnet
;
ipnet : ipaddr
| ipaddr '/' netbits
| ipaddr '/' netmask
| '*'
| '!' ipnet
;
ports : port
| '{' sp listports sp '}'
;
listports : port
| listports sp ',' sp port
;
port : number
| '*'
| '!' port
;
netbits : number
;
netmask : byte '.' byte '.' byte '.' byte
;
ipaddr : byte '.' byte '.' byte '.' byte
;
byte : number
;
number : DIGIT
| number DIGIT
;
sp :
| spaces
;
spaces : SP
| spaces SP
;
filter exmple:
1. src-ip 10.1.1.1 dst-ip {!10.1.1.1,10.0.0.0/8} proto {tcp,udp}
2. src-ip !10.1.1.0/24 (src-port {10,11,12} || dst-port 5)
3. ! src-ip 10.1.1.1
4. src-ip !10.1.1.1
5. src-ip !{10.1.1.1,10.1.1.2}
6. src-ip {!10.1.1.1,10.1.1.2}
7. ! src-ip ! {!10.1.1.1}
8. proto *
flow-merge2 example:
flow-merge2 -f 'src-ip 10.1.1.1 ! dst-ip { 10.0.0.0/8 }' /var/db/flows
I want to contribute this code to flow-tools. Please.
/swp
/*
* Copyright (c) 2001 E. Larry Lidz
* Copyright (c) 2008 Alexander Mitrokhin
* Portions 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: flow-merge.c,v 1.9 2003/04/02 18:03:02 maf Exp $
*/
#include "ftconfig.h"
#include <ftlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include "ippf.h"
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
static inline
void
usage(void)
{
fprintf(stderr, "Usage: flow-merge [-aghm] [-b big|little] [-C comment] [-d debug_level]\n"
" [-o filename] [-z z_level] [file|directory ...]\n");
}
int debug;
struct ftio_table {
char *cur_entry;
struct ftio ftio_data;
};
int find_earliest(struct ftio_table ftio_entry[], int num_entries);
int main(int argc, char **argv)
{
struct stat sb;
struct ftio ftio_out;
struct ftprof ftp;
struct ftver ftv, ftv2;
struct ftset ftset;
struct ftfile_entries *fte;
struct ftfile_entry *fty;
struct ftio_table *ftio_array;
int out_fd, out_fd_plain, in_fd, disable_mmap, in_fd_plain, sort;
int ftio_entries;
int fd, flags, fte_entries;
char *fname, *out_fname;
u_int32 total_flows;
u_int32 time_start, time_end, time_tmp;
struct ippf *f;
fterr_setid(argv[0]);
ftprof_start (&ftp);
bzero(&ftv, sizeof ftv);
bzero(&ftv2, sizeof ftv2);
/* defaults + no compression */
ftset_init(&ftset, 0);
total_flows = 0;
out_fd_plain = 0;
out_fname = (char*)0L;
out_fd = -1;
time_start = -1; /* MAXINT */
time_end = 0;
disable_mmap = 0;
sort = 0; /* global sorting disabled by default */
fte_entries = 0;
flags = FT_FILE_INIT | FT_FILE_SORT | FT_FILE_SKIPTMP;
ftio_entries = 0;
f = 0;
do {
int c;
while ((c = getopt(argc, argv, "ab:C:d:f:gh?mo:i:z:")) != -1)
switch (c) {
case 'a': /* all files, even those with tmp */
flags &= ~FT_FILE_SKIPTMP;
break;
case 'b': /* output byte order */
if (!strcasecmp(optarg, "little"))
ftset.byte_order = FT_HEADER_LITTLE_ENDIAN;
else if (!strcasecmp(optarg, "big"))
ftset.byte_order = FT_HEADER_BIG_ENDIAN;
else
fterr_errx(1, "expecting \"big\" or \"little\"");
break;
case 'C': /* comment field */
ftset.comments = optarg;
break;
case 'd': /* debug */
debug = atoi(optarg);
break;
case 'f':
f = ippf_create_str(optarg);
if (!f)
fterr_errx(1, "filter compilation error");
break;
case 'g': /* global sort */
sort = 1;
break;
case 'm': /* disable mmap */
disable_mmap = 1;
break;
case 'o': /* output filename */
out_fname = optarg;
break;
case 'z': /* compress level */
ftset.z_level = atoi(optarg);
if ((ftset.z_level < 0) || (ftset.z_level > 9))
fterr_errx(1, "Compression level must be between 0 and 9");
break;
case 'h': /* help */
case '?':
default:
usage();
exit (1);
break;
} /* switch */
} while (0);
/* if out_fname is not set, then use stdout */
if (out_fname) {
if ((out_fd = open(out_fname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
fterr_err(1, "open(%s)", out_fname);
if (fstat(out_fd, &sb) == -1)
fterr_err(1, "fstat(%s)", out_fname);
/* is this a plain file? */
if (S_ISREG(sb.st_mode))
out_fd_plain = 1;
} else
out_fd = 1;
/* output to out_fd */
if (ftio_init(&ftio_out, out_fd, FT_IO_FLAG_WRITE |
((ftset.z_level) ? FT_IO_FLAG_ZINIT : 0) ) < 0)
fterr_errx(1, "ftio_init(): failed");
ftio_set_comment(&ftio_out, ftset.comments);
ftio_set_byte_order(&ftio_out, ftset.byte_order);
ftio_set_z_level(&ftio_out, ftset.z_level);
ftio_set_streaming(&ftio_out, 1);
ftio_set_debug(&ftio_out, debug);
/* header must be full size on initial write */
if (out_fd_plain) {
ftio_set_cap_time(&ftio_out, time_start, time_end);
ftio_set_flows_count(&ftio_out, total_flows);
}
/* number of file lists */
fte_entries = argc - optind;
/* always at least one entry */
if (fte_entries <= 0)
fte_entries = 1;
if (sort)
fte_entries = 1;
/* allocate space for ftfile_entries lists */
if (!(fte = malloc(sizeof (struct ftfile_entries) * fte_entries)))
fterr_err(1, "malloc()");
bzero(fte, sizeof(struct ftfile_entries) * fte_entries);
/* handle special case of stdin (no args) */
if (optind >= argc) {
/* "" will be treated as stdin below */
if (ftfile_loadfile(&fte[0], "", flags) < 0)
fterr_errx(1, "ftfile_loadfile(%s)", "");
} else {
int i, x;
for (i = optind, x = 0; i < argc; ++i) {
fname = argv[i];
/* special case, stdin */
if ((fname[0] == '-') && (fname[1] == 0)) {
/* "" will be treated as stdin below */
if (ftfile_loadfile(fte + x, "", flags) < 0)
fterr_errx(1, "ftfile_loadfile(%s)", "");
goto skip1;
}
if (stat(fname, &sb) < 0)
fterr_err(1, "fstat(%s)", fname);
if (S_ISREG(sb.st_mode)) {
/* is this a plain file? */
if (ftfile_loadfile(fte + x, fname, flags) < 0)
fterr_errx(1, "ftfile_loadfile(%s)", fname);
} else if (S_ISDIR(sb.st_mode)) {
/* else is this a directory? */
if (ftfile_loaddir(fte + x, fname, flags) < 0)
fterr_errx(1, "ftfile_loaddir(%s), fname");
} else {
fterr_warnx("odd file, skipping: %s", fname);
continue;
}
skip1:
/* if not sorting, use next list (sorting requires one list) */
if (!sort)
++x;
else
/* else, the list is initialized, don't do it again */
flags &= ~FT_FILE_INIT;
}
}
/* dump list of files loaded */
if (debug > 5) {
int i;
for (i = 0; i < fte_entries; ++i) {
fterr_info(" i=%d", i);
ftfile_dump(fte + i);
}
}
do {
int i;
/* count total entries */
for (i = 0; i < fte_entries; ++i)
/* foreach file in the list */
FT_TAILQ_FOREACH(fty, &fte[i].head, chain)
ftio_entries++;
} while (0);
ftio_array = malloc(ftio_entries * sizeof(struct ftio_table));
if (!ftio_array)
fterr_errx(1, "malloc()");
bzero(ftio_array, ftio_entries * sizeof(struct ftio_table));
do {
int i, j;
/* foreach list */
for (i = j = 0; i < fte_entries; ++i) {
/* foreach file in the list */
FT_TAILQ_FOREACH(fty, &fte[i].head, chain) {
/* stdin / real file? */
if (fty->name[0]) {
in_fd_plain = 1;
if ((in_fd = open(fty->name, O_RDONLY, 0)) == -1) {
fterr_warn("open(%s)", fty->name);
continue;
}
} else {
in_fd_plain = 0;
in_fd = 0; /* stdin */
}
/* initialize ftio stream */
if (ftio_init(&ftio_array[j].ftio_data, in_fd, FT_IO_FLAG_READ |
((in_fd_plain && !disable_mmap) ? FT_IO_FLAG_MMAP : 0)) < 0)
fterr_errx(1, "ftio_init(): failed");
/* ensure required fields */
if (ftio_check_xfield(&ftio_array[j].ftio_data,
FT_XFIELD_UNIX_SECS|FT_XFIELD_UNIX_NSECS|FT_XFIELD_SYSUPTIME|
FT_XFIELD_FIRST|FT_XFIELD_LAST))
fterr_errx(1, "Flow record missing required field.");
/* get version from stream */
ftio_get_ver(&ftio_array[j].ftio_data, &ftv2);
/* record smallest time */
time_tmp = ftio_get_cap_start(&ftio_array[j].ftio_data);
if (time_tmp < time_start)
time_start = time_tmp;
/* record largest time */
time_tmp = ftio_get_cap_end(&ftio_array[j].ftio_data);
if (time_tmp > time_end)
time_end = time_tmp;
/* first time through loop? */
if (!ftv.d_version) {
/*
* is this really the right thing to do here. Reading a v1
* stream gets handled by ftio_read(), but ftio_* leaves the
* s_version at 1.
*/
ftv2.s_version = FT_IO_SVERSION;
/* set the version information in the io stream */
if (ftio_set_ver(&ftio_out, &ftv2) < 0)
fterr_errx(1, "ftio_set_ver(): failed");
/* save for later compare */
bcopy(&ftv2, &ftv, sizeof ftv);
/* header first */
if (ftio_write_header(&ftio_out) < 0)
fterr_errx(1, "ftio_write_header(): failed");
} else {
/* ensure previous version == current version */
if ((ftv.d_version != ftv2.d_version) ||
(ftv.agg_method != ftv2.agg_method))
fterr_errx(1, "data version or sub version changed!");
}
/* get the next element into the cur_entry field */
/* this is so it can be compared in find_earliest */
ftio_array[j].cur_entry = ftio_read(&ftio_array[j].ftio_data);
j++;
}
}
} while (0);
do {
int entry;
#define FT_FIELD(ftio, r, field, type) \
(*(type *)(((char *)(r)) + (ftio)->fo.field))
#define FT_SRCADDR(ftio, r) FT_FIELD(ftio, r, srcaddr, in_addr_t)
#define FT_DSTADDR(ftio, r) FT_FIELD(ftio, r, dstaddr, in_addr_t)
#define FT_SRCPORT(ftio, r) FT_FIELD(ftio, r, srcport, uint16_t)
#define FT_DSTPORT(ftio, r) FT_FIELD(ftio, r, dstport, uint16_t)
#define FT_DOCTETS(ftio, r) FT_FIELD(ftio, r, dOctets, uint32_t)
#define FT_IPPROTO(ftio, r) FT_FIELD(ftio, r, prot, uint8_t)
for (; (entry = find_earliest(ftio_array, ftio_entries)) >= 0; ) {
if (f && ippf_calc(f,
FT_IPPROTO(&ftio_array[entry].ftio_data, ftio_array[entry].cur_entry),
FT_SRCADDR(&ftio_array[entry].ftio_data, ftio_array[entry].cur_entry),
FT_SRCPORT(&ftio_array[entry].ftio_data, ftio_array[entry].cur_entry),
FT_DSTADDR(&ftio_array[entry].ftio_data, ftio_array[entry].cur_entry),
FT_DSTPORT(&ftio_array[entry].ftio_data, ftio_array[entry].cur_entry)))
/* copy the earliest entry in ftio_array */
if (ftio_write(&ftio_out, ftio_array[entry].cur_entry) < 0)
fterr_errx(1, "ftio_write(): failed");
/* get the next element into the cur_entry field */
ftio_array[entry].cur_entry = ftio_read(&ftio_array[entry].ftio_data);
++total_flows;
}
} while (0);
do {
int i;
for (i = 0; i < ftio_entries; i++)
/* done with input stream */
if (ftio_close(&ftio_array[i].ftio_data) < 0)
fterr_errx(1, "ftio_close(): failed");
} while (0);
/*
* if the output file descriptor was a real file, re-write the
* flow_header with the correct # of total flows
*/
if (out_fd_plain) {
ftio_set_cap_time(&ftio_out, time_start, time_end);
ftio_set_flows_count(&ftio_out, total_flows);
ftio_set_streaming(&ftio_out, 0);
if (ftio_write_header(&ftio_out) < 0)
fterr_errx(1, "ftio_write_header(): failed");
}
/* done with output stream */
if (ftio_close(&ftio_out) < 0)
fterr_errx(1, "ftio_close(): failed");
if (debug > 0) {
ftprof_end (&ftp, total_flows);
ftprof_print(&ftp, argv[0], stderr);
}
free(ftio_array);
free(fte);
if (f)
ippf_destroy(f);
return 0;
}
int
find_earliest(struct ftio_table ftio_entry[], int num_entries)
{
unsigned int i, earliest_offset;
register struct timeval earliest_time;
struct fts3rec_all cur;
struct fttime ftt;
int first;
earliest_offset = -1;
first = 0;
for (i = 0; i < num_entries; i++) {
/* already read all the entries in this file */
if (ftio_entry[i].cur_entry == NULL)
continue;
cur.unix_secs = ((u_int32*)(ftio_entry[i].cur_entry+
ftio_entry[i].ftio_data.fo.unix_secs));
cur.unix_nsecs = ((u_int32*)(ftio_entry[i].cur_entry+
ftio_entry[i].ftio_data.fo.unix_nsecs));
cur.sysUpTime = ((u_int32*)(ftio_entry[i].cur_entry+
ftio_entry[i].ftio_data.fo.sysUpTime));
cur.Last = ((u_int32*)(ftio_entry[i].cur_entry+
ftio_entry[i].ftio_data.fo.Last));
ftt = ftltime(*cur.sysUpTime, *cur.unix_secs,
*cur.unix_nsecs, *cur.Last);
if (first == 0) { /* first entry is the earliest by default */
earliest_offset = i;
earliest_time.tv_sec = ftt.secs;
earliest_time.tv_usec = ftt.msecs;
first = 1;
} else
if ((ftt.secs < earliest_time.tv_sec) ||
(ftt.secs == earliest_time.tv_sec &&
(ftt.msecs < earliest_time.tv_usec))) {
earliest_offset = i;
earliest_time.tv_sec = ftt.secs;
earliest_time.tv_usec = ftt.msecs;
}
}
return earliest_offset;
}
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <err.h>
#define ELOG(fmt, args...) warnx(fmt, ##args)
#define WLOG(fmt, args...) warnx(fmt, ##args)
#include "ippf.h"
enum action
{ ALLOW = 1, DENY = 0 };
enum ltype
{ LTYPE_PROTO, LTYPE_IPNET, LTYPE_PORT };
struct proto {
enum action act;
int proto;
};
struct ipnet {
enum action act;
in_addr_t addr;
in_addr_t mask;
};
struct port {
enum action act;
int port;
};
struct node {
int n;
union {
enum action act;
struct proto proto;
struct ipnet ipnet;
struct port port;
} ar[0x10];
STAILQ_ENTRY(node) ent;
};
STAILQ_HEAD(list, node);
static
int
list_add(struct list *list, enum ltype ltype, ...)
{
struct node *p;
va_list ap;
p = STAILQ_LAST(list, node, ent);
if (!p || p->n == sizeof p->ar / sizeof p->ar[0]) {
p = malloc(sizeof *p);
if (!p)
return 1;
p->n = 0;
STAILQ_INSERT_TAIL(list, p, ent);
}
va_start(ap, ltype);
if (ltype == LTYPE_PROTO)
p->ar[p->n].proto = *va_arg(ap, typeof(p->ar[0].proto) *);
else if (ltype == LTYPE_IPNET)
p->ar[p->n].ipnet = *va_arg(ap, typeof(p->ar[0].ipnet) *);
else /* if (ltype == LTYPE_PORT) */
p->ar[p->n].port = *va_arg(ap, typeof(p->ar[0].port) *);
va_end(ap);
p->n++;
return 0;
}
static
void
list_clear(struct list *list)
{
struct node *p, *q;
for (p = STAILQ_FIRST(list); p; p = q) {
q = STAILQ_NEXT(p, ent);
free(p);
}
STAILQ_INIT(list);
}
enum exprtype {
EXPR_NONE,
EXPR_PROTO,
EXPR_IP,
EXPR_SRCIP,
EXPR_DSTIP,
EXPR_PORT,
EXPR_SRCPORT,
EXPR_DSTPORT,
EXPR_NOT,
EXPR_OR,
EXPR_AND
};
struct expr_proto {
enum exprtype type;
struct list list[1];
};
struct expr_ip {
enum exprtype type;
struct list list[1];
};
struct expr_srcip {
enum exprtype type;
struct list list[1];
};
struct expr_dstip {
enum exprtype type;
struct list list[1];
};
struct expr_port {
enum exprtype type;
struct list list[1];
};
struct expr_srcport {
enum exprtype type;
struct list list[1];
};
struct expr_dstport {
enum exprtype type;
struct list list[1];
};
struct expr_not {
enum exprtype type;
union expr * op;
};
struct expr_or {
enum exprtype type;
union expr * op[2];
};
struct expr_and {
enum exprtype type;
union expr * op[2];
};
union expr {
enum exprtype type;
struct expr_proto expr_proto;
struct expr_ip expr_ip;
struct expr_srcip expr_srcip;
struct expr_dstip expr_dstip;
struct expr_port expr_port;
struct expr_srcport expr_srcport;
struct expr_dstport expr_dstport;
struct expr_not expr_not;
struct expr_or expr_or;
struct expr_and expr_and;
};
static
void
expr_clear(union expr *expr)
{
if (expr->type == EXPR_PROTO)
list_clear(expr->expr_proto.list);
else if (expr->type == EXPR_IP)
list_clear(expr->expr_ip.list);
else if (expr->type == EXPR_SRCIP)
list_clear(expr->expr_srcip.list);
else if (expr->type == EXPR_DSTIP)
list_clear(expr->expr_dstip.list);
else if (expr->type == EXPR_PORT)
list_clear(expr->expr_port.list);
else if (expr->type == EXPR_SRCPORT)
list_clear(expr->expr_srcport.list);
else if (expr->type == EXPR_DSTPORT)
list_clear(expr->expr_dstport.list);
else if (expr->type == EXPR_NOT) {
expr_clear(expr->expr_not.op);
free(expr->expr_not.op);
} else if (expr->type == EXPR_OR) {
expr_clear(expr->expr_or.op[0]);
free(expr->expr_or.op[0]);
expr_clear(expr->expr_or.op[1]);
free(expr->expr_or.op[1]);
} else if (expr->type == EXPR_AND) {
expr_clear(expr->expr_and.op[0]);
free(expr->expr_and.op[0]);
expr_clear(expr->expr_and.op[1]);
free(expr->expr_and.op[1]);
} else if (expr->type == EXPR_NONE)
WLOG("expr_clear(): EXPR_NONE: ???");
else
WLOG("expr_clear(): %d: unknown enum exprtype", expr->type);
expr->type = EXPR_NONE;
}
static
void
expr_destroy(union expr *expr)
{
if (expr) {
expr_clear(expr);
free(expr);
}
}
static
int
expr_calc(union expr *expr, int proto, in_addr_t srcip, int srcport, in_addr_t
dstip, int dstport)
{
int rc;
struct node *p;
int i;
rc = DENY;
if (!expr)
rc = ALLOW;
else if (expr->type == EXPR_PROTO) {
STAILQ_FOREACH(p, expr->expr_proto.list, ent)
for (i = 0; i < p->n; i++)
if (!p->ar[i].proto.proto ||
p->ar[i].proto.proto == proto) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_IP) {
STAILQ_FOREACH(p, expr->expr_ip.list, ent)
for (i = 0; i < p->n; i++)
if (p->ar[i].ipnet.addr == (srcip &
p->ar[i].ipnet.mask) ||
p->ar[i].ipnet.addr == (dstip &
p->ar[i].ipnet.mask)) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_SRCIP) {
STAILQ_FOREACH(p, expr->expr_srcip.list, ent)
for (i = 0; i < p->n; i++)
if (p->ar[i].ipnet.addr == (srcip &
p->ar[i].ipnet.mask)) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_DSTIP) {
STAILQ_FOREACH(p, expr->expr_dstip.list, ent)
for (i = 0; i < p->n; i++)
if (p->ar[i].ipnet.addr == (dstip &
p->ar[i].ipnet.mask)) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_PORT) {
STAILQ_FOREACH(p, expr->expr_port.list, ent)
for (i = 0; i < p->n; i++)
if (p->ar[i].port.port == 0
|| p->ar[i].port.port == srcport
|| p->ar[i].port.port ==
dstport) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_SRCPORT) {
STAILQ_FOREACH(p, expr->expr_srcport.list, ent)
for (i = 0; i < p->n; i++)
if (p->ar[i].port.port == 0 ||
p->ar[i].port.port == srcport) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_DSTPORT) {
STAILQ_FOREACH(p, expr->expr_dstport.list, ent)
for (i = 0; i < p->n; i++)
if (p->ar[i].port.port == 0 ||
p->ar[i].port.port == dstport) {
rc = p->ar[i].act;
goto L1;
}
} else if (expr->type == EXPR_NOT)
rc = !expr_calc(expr->expr_not.op, proto, srcip, srcport,
dstip, dstport);
else if (expr->type == EXPR_OR)
rc = expr_calc(expr->expr_or.op[0], proto, srcip, srcport,
dstip, dstport) ||
expr_calc(expr->expr_or.op[1], proto, srcip, srcport,
dstip, dstport);
else if (expr->type == EXPR_AND)
rc = expr_calc(expr->expr_and.op[0], proto, srcip, srcport,
dstip, dstport) &&
expr_calc(expr->expr_and.op[1], proto, srcip, srcport,
dstip, dstport);
L1:
return rc;
}
%}
%union {
union expr * expr_p;
struct list list;
struct proto proto;
struct ipnet ipnet;
struct port port;
in_addr_t ipaddr;
int d;
}
%type <expr_p> cond
%type <expr_p> expr
%type <list> protos
%type <list> listprotos
%type <list> ipnets
%type <list> listipnets
%type <list> ports
%type <list> listports
%type <proto> proto
%type <ipnet> ipnet
%type <port> port
%type <ipaddr> ipaddr
%type <d> netbits
%type <d> netmask
%type <d> byte
%type <d> number
%token <d> DIGIT
%token SP
%destructor { expr_destroy($$); } expr cond
%destructor { list_clear(&$$); } listports ports listipnets ipnets listprotos
protos
%pure-parser
%locations
%parse-param { FILE *fp }
%parse-param { union expr **expr }
%lex-param { FILE *fp }
%error-verbose
%initial-action
{
}
%{
static int yyparse(FILE *fp, union expr **expr);
static int yyerror(YYLTYPE *llocp, FILE *fp, union expr **expr, char const
*msg);
static int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, FILE *fp);
%}
%%
start : sp
{
*expr = 0;
}
| sp cond sp
{
*expr = $2;
$2 = 0;
}
;
cond : expr
{
$$ = $1;
$1 = 0;
}
| cond spaces expr
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_and",
@$.first_line, @$.first_column);
YYABORT;
}
$$->type = EXPR_AND;
$$->expr_and.op[0] = $1;
$1 = 0;
$$->expr_and.op[1] = $3;
$3 = 0;
}
| cond sp '|' '|' sp expr
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_and",
@$.first_line, @$.first_column);
YYABORT;
}
$$->type = EXPR_OR;
$$->expr_or.op[0] = $1;
$1 = 0;
$$->expr_or.op[1] = $6;
$6 = 0;
}
;
expr : 'p' 'r' 'o' 't' 'o' spaces protos
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_proto",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_PROTO;
STAILQ_INIT($$->expr_proto.list);
STAILQ_CONCAT($$->expr_proto.list, &$7);
STAILQ_INIT(&$7);
}
| 'i' 'p' spaces ipnets
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create expr_ip",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_IP;
STAILQ_INIT($$->expr_ip.list);
STAILQ_CONCAT($$->expr_ip.list, &$4);
STAILQ_INIT(&$4);
}
| 's' 'r' 'c' '-' 'i' 'p' spaces ipnets
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_srcip",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_SRCIP;
STAILQ_INIT($$->expr_srcip.list);
STAILQ_CONCAT($$->expr_srcip.list, &$8);
STAILQ_INIT(&$8);
}
| 'd' 's' 't' '-' 'i' 'p' spaces ipnets
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_dstip",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_DSTIP;
STAILQ_INIT($$->expr_dstip.list);
STAILQ_CONCAT($$->expr_dstip.list, &$8);
STAILQ_INIT(&$8);
}
| 'p' 'o' 'r' 't' spaces ports
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_srcport",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_PORT;
STAILQ_INIT($$->expr_srcport.list);
STAILQ_CONCAT($$->expr_srcport.list, &$6);
STAILQ_INIT(&$6);
}
| 's' 'r' 'c' '-' 'p' 'o' 'r' 't' spaces ports
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_srcport",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_SRCPORT;
STAILQ_INIT($$->expr_srcport.list);
STAILQ_CONCAT($$->expr_srcport.list, &$10);
STAILQ_INIT(&$10);
}
| 'd' 's' 't' '-' 'p' 'o' 'r' 't' spaces ports
{
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_dstport",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_DSTPORT;
STAILQ_INIT($$->expr_dstport.list);
STAILQ_CONCAT($$->expr_dstport.list, &$10);
STAILQ_INIT(&$10);
}
| '!' sp expr
{
if ($3->type == EXPR_NOT) {
$$ = $3->expr_not.op;
free($3);
} else {
if (!($$ = malloc(sizeof *$$))) {
ELOG("(l%d,c%d): unable create
expr_not",
@$.first_line,
@$.first_column);
YYABORT;
}
$$->type = EXPR_NOT;
$$->expr_not.op = $3;
$3 = 0;
}
}
| '(' sp cond sp ')'
{
$$ = $3;
$3 = 0;
}
;
protos : proto
{
STAILQ_INIT(&$$);
if (list_add(&$$, LTYPE_PORT, &$1)) {
ELOG("(l%d,c%d): %d: unable insert
proto in list",
@$.first_line, @$.first_column,
$1.proto);
YYABORT;
}
}
| '{' sp listprotos sp '}'
{
STAILQ_INIT(&$$);
STAILQ_CONCAT(&$$, &$3);
STAILQ_INIT(&$3);
}
;
listprotos : proto
{
STAILQ_INIT(&$$);
if (list_add(&$$, LTYPE_PORT, &$1)) {
ELOG("(l%d,c%d): %d: unable insert
proto in list",
@$.first_line, @$.first_column,
$1.proto);
YYABORT;
}
}
| listprotos sp ',' sp proto
{
STAILQ_INIT(&$$);
if (list_add(&$1, LTYPE_PORT, &$5)) {
ELOG("(l%d,c%d): %d: unable insert
proto in list",
@$.first_line, @$.first_column,
$5.proto);
YYABORT;
}
STAILQ_CONCAT(&$$, &$1);
STAILQ_INIT(&$1);
}
;
proto : 'i' 'p'
{
struct protoent *p;
if (!(p = getprotobyname("ip"))) {
ELOG("(l%d,c%d):
getprotobyname(\"ip\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| 'i' 'c' 'm' 'p'
{
struct protoent *p;
if (!(p = getprotobyname("icmp"))) {
ELOG("(l%d,c%d):
getprotobyname(\"icmp\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| 't' 'c' 'p'
{
struct protoent *p;
if (!(p = getprotobyname("tcp"))) {
ELOG("(l%d,c%d):
getprotobyname(\"tcp\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| 'u' 'd' 'p'
{
struct protoent *p;
if (!(p = getprotobyname("udp"))) {
ELOG("(l%d,c%d):
getprotobyname(\"udp\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| 'i' 'p' 'e' 'n' 'c' 'a' 'p'
{
struct protoent *p;
if (!(p = getprotobyname("ipencap"))) {
ELOG("(l%d,c%d):
getprotobyname(\"ipencap\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| 'g' 'r' 'e'
{
struct protoent *p;
if (!(p = getprotobyname("gre"))) {
ELOG("(l%d,c%d):
getprotobyname(\"gre\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| '*'
{
struct protoent *p;
if (!(p = getprotobyname("ip"))) {
ELOG("(l%d,c%d):
getprotobyname(\"ip\"): not found\n",
@$.first_line, @$.first_column);
YYABORT;
}
$$.proto = p->p_proto;
$$.act = ALLOW;
}
| number
{
$$.proto = $1;
$$.act = ALLOW;
}
| '!' proto
{
$$.proto = $2.proto;
$$.act = !$2.act;
}
;
ipnets : ipnet
{
STAILQ_INIT(&$$);
if (list_add(&$$, LTYPE_IPNET, &$1)) {
in_addr_t addr = htonl($1.addr);
in_addr_t mask = htonl($1.mask);
char addrbuf[0x10], maskbuf[0x10];
ELOG("(l%d,c%d): %s/%s: unable insert
ipnetwork in list",
@$.first_line, @$.first_column,
inet_ntop(AF_INET,
&addr, addrbuf, sizeof addrbuf),
inet_ntop(AF_INET,
&mask, maskbuf, sizeof maskbuf));
YYABORT;
}
}
| '{' sp listipnets sp '}'
{
STAILQ_INIT(&$$);
STAILQ_CONCAT(&$$, &$3);
STAILQ_INIT(&$3);
}
;
listipnets : ipnet
{
STAILQ_INIT(&$$);
if (list_add(&$$, LTYPE_IPNET, &$1)) {
in_addr_t addr = htonl($1.addr);
in_addr_t mask = htonl($1.mask);
char addrbuf[0x10], maskbuf[0x10];
ELOG("(l%d,c%d): %s/%s: unable insert
ipnetwork in list",
@$.first_line, @$.first_column,
inet_ntop(AF_INET,
&addr, addrbuf, sizeof addrbuf),
inet_ntop(AF_INET,
&mask, maskbuf, sizeof maskbuf));
YYABORT;
}
}
| listipnets sp ',' sp ipnet
{
STAILQ_INIT(&$$);
if (list_add(&$1, LTYPE_IPNET, &$5)) {
in_addr_t addr = htonl($5.addr);
in_addr_t mask = htonl($5.mask);
char addrbuf[0x10], maskbuf[0x10];
ELOG("(l%d,c%d): %s/%s: unable insert
ipnetwork in list",
@$.first_line, @$.first_column,
inet_ntop(AF_INET,
&addr, addrbuf, sizeof addrbuf),
inet_ntop(AF_INET,
&mask, maskbuf, sizeof maskbuf));
YYABORT;
}
STAILQ_CONCAT(&$$, &$1);
STAILQ_INIT(&$1);
}
;
ipnet : ipaddr
{
$$.addr = $1;
$$.mask = -1;
$$.act = ALLOW;
}
| ipaddr '/' netbits
{
$$.addr = $1;
$$.mask = $3 ? -1<<(32-$3) : 0;
$$.act = ALLOW;
}
| ipaddr '/' netmask
{
$$.addr = $1;
$$.mask = $3;
$$.act = ALLOW;
}
| '*'
{
$$.addr = 0;
$$.mask = 0;
$$.act = ALLOW;
}
| '!' ipnet
{
$$.addr = $2.addr;
$$.mask = $2.mask;
$$.act = !$2.act;
}
;
ports : port
{
STAILQ_INIT(&$$);
if (list_add(&$$, LTYPE_PORT, &$1)) {
ELOG("(l%d,c%d): %d: unable insert port
in list",
@$.first_line, @$.first_column,
$1.port);
YYABORT;
}
}
| '{' sp listports sp '}'
{
STAILQ_INIT(&$$);
STAILQ_CONCAT(&$$, &$3);
STAILQ_INIT(&$3);
}
;
listports : port
{
STAILQ_INIT(&$$);
if (list_add(&$$, LTYPE_PORT, &$1)) {
ELOG("(l%d,c%d): %d: unable insert port
in list",
@$.first_line, @$.first_column,
$1.port);
YYABORT;
}
}
| listports sp ',' sp port
{
STAILQ_INIT(&$$);
if (list_add(&$1, LTYPE_PORT, &$5)) {
ELOG("(l%d,c%d): %d: unable insert port
in list",
@$.first_line, @$.first_column,
$5.port);
YYABORT;
}
STAILQ_CONCAT(&$$, &$1);
STAILQ_INIT(&$1);
}
;
port : number
{
if ($1 > 65535) {
ELOG("(l%d,c%d): %d: wrong port number",
@$.first_line, @$.first_column,
$1);
YYABORT;
}
$$.port = $1;
$$.act = ALLOW;
}
| '*'
{
$$.port = 0;
$$.act = ALLOW;
}
| '!' port
{
$$.port = $2.port;
$$.act = !$2.act;
}
;
netbits : number
{
$$ = $1;
if ($1 > 32) {
ELOG("(l%d,c%d): %d: wrong bitmask",
@$.first_line, @$.first_column,
$1);
YYABORT;
}
}
;
netmask : byte '.' byte '.' byte '.' byte
{
$$ = (($7&0377)<<24) | (($5&0377)<<16) |
(($3&0377)<<8) | ($1&0377);
$$ = ntohl($$);
}
;
ipaddr : byte '.' byte '.' byte '.' byte
{
$$ = (($7&0377)<<24) | (($5&0377)<<16) |
(($3&0377)<<8) | ($1&0377);
$$ = ntohl($$);
}
;
byte : number
{
$$ = $1;
if ($1 > 255) {
ELOG("(l%d,c%d): %d: expect byte",
@$.first_line, @$.first_column,
$1);
YYABORT;
}
}
;
number : DIGIT
{
$$ = $1;
}
| number DIGIT
{
$$ = $1 * 10 + $2;
if ($$ < $1) {
ELOG("(l%d,c%d): big number",
@$.first_line, @$.first_column);
YYABORT;
}
}
;
sp :
| spaces
;
spaces : SP
| spaces SP
;
%%
int
yyerror(YYLTYPE *llocp, FILE *fp, union expr **expr, char const *msg)
{
fprintf(stderr, "ERROR(%d:%d-%d:%d): %s\n",
llocp->first_line, llocp->first_column,
llocp->last_line, llocp->last_column,
msg);
return 0;
}
int
yylex(YYSTYPE *lvalp, YYLTYPE *llocp, FILE *fp)
{
int c;
if ((c = fgetc(fp)) >= 0) {
if (c == '\n') {
llocp->first_line = ++llocp->last_line;
llocp->first_column = llocp->last_column = 0;
} else
llocp->first_column = ++llocp->last_column;
if (isspace(c)) {
c = SP;
} else if (isdigit(c)) {
lvalp->d = c - '0';
c = DIGIT;
}
}
return c;
}
struct ippf *
ippf_create(FILE *fp)
{
union expr *expr;
if (yyparse(fp, &expr)) {
expr_destroy(expr);
expr = 0;
}
return (struct ippf *)expr;
}
void
ippf_destroy(struct ippf *filt)
{
if (filt)
expr_destroy((union expr *)filt);
}
static
int
str_readfn(void *cookie, char *buf, int n)
{
int r;
r = strlcpy(buf, *(char **)cookie, n);
*(char **)cookie += r;
return r;
}
struct ippf *
ippf_create_str(char const *s)
{
struct ippf *filt;
FILE *fp;
filt = 0;
if ((fp = fropen(&s, str_readfn)) != 0) {
filt = ippf_create(fp);
fclose(fp);
}
return filt;
}
int
ippf_calc(struct ippf *filt, int proto, in_addr_t srcip, int srcport, in_addr_t
dstip, int dstport)
{
return expr_calc((union expr *)filt, proto, srcip, srcport, dstip,
dstport);
}
/* $Id: ippf.h,v 1.1 2007/08/13 17:55:33 swp Exp $ */
#ifndef __ippf_h__
#define __ippf_h__
#include <sys/cdefs.h>
struct ippf;
__BEGIN_DECLS
struct ippf * ippf_create(FILE *);
struct ippf * ippf_create_str(char const *);
void ippf_destroy(struct ippf *);
int ippf_calc(struct ippf *, int, in_addr_t, int, in_addr_t, int);
__END_DECLS
#endif
_______________________________________________
Flow-tools mailing list
[EMAIL PROTECTED]
http://mailman.splintered.net/mailman/listinfo/flow-tools