#include #include #include #include #include #include #include "../include/ebtables_u.h" #include "../include/ethernetdb.h" #include #include /* #define DEBUG */ #define AMONG_DST '1' #define AMONG_SRC '2' static struct option opts[] = { { "among-dst" , required_argument, 0, AMONG_DST }, { "among-src" , required_argument, 0, AMONG_SRC }, { 0 } }; #ifdef DEBUG static void hexdump(const void *mem, int howmany) { printf("\n"); const unsigned char *p = mem; int i; for (i = 0; i < howmany; i++) { if (i % 32 == 0) { printf("\n%04x: ", i); } printf("%2.2x ", p[i]); } printf("\n"); } #endif /* DEBUG */ static void print_help() { printf( "`among' options:\n" "--among-dst list : matches if ether dst is in list\n" "--among-src list : matches if ether src is in list\n" "list has form:\n" "\txx:xx:xx:xx:xx:xx,yy:yy:yy:yy:yy:yy,...,zz:zz:zz:zz:zz:zz\n" "i.e. MAC addresses separated by commas, without spaces.\n" "Optional comma can be included after the last MAC address, i.e.:\n" "\txx:xx:xx:xx:xx:xx,yy:yy:yy:yy:yy:yy,...,zz:zz:zz:zz:zz:zz,\n" "Each list can contain up to 256 addresses.\n" ); } static void init(struct ebt_entry_match *match) { struct ebt_among_info *amonginfo = (struct ebt_among_info *)match->data; memset(amonginfo, 0, sizeof(struct ebt_among_info)); } static int fill_mac(char *mac, const char *string) { char xnum[3]; const char *p = string; int i = 0; int j = 0; while (1) { if (isxdigit(*p)) { xnum[j] = *p; j++; if (j >= 3) { /* 3 or more hex digits for a single byte */ return -3; } } else { xnum[j] = 0; j = 0; mac[i] = strtol(xnum, 0, 16); i++; if (i >= 6) { if (*p == ':') { /* MAC address too long */ return -2; } else { return 0; } } else { if (*p != ':') { /* MAC address too short */ return -1; } } } p++; } } static void fill_wormhash(struct ebt_mac_wormhash *wh, const char *arg) { const char *pc = arg; const char *anchor; char mac[6]; int index; int nmacs = 0; char *base = (char*)wh; memset(wh, 0, sizeof(struct ebt_mac_wormhash)); while (1) { anchor = pc; while (*pc && *pc != ',') pc++; while (*pc && *pc == ',') pc++; if (fill_mac(mac, anchor)) { print_error("problem with MAC %20s...", anchor); } index = (unsigned char)mac[5]; memcpy(((char*)wh->pool[nmacs].cmp)+2, mac, 6); wh->pool[nmacs].next_ofs = wh->table[index]; wh->table[index] = ((const char*)&wh->pool[nmacs]) - base; nmacs++; if (*pc && nmacs >= 256) { print_error("--among-src/--among-dst list can contain no more than 256 addresses\n"); } if (!*pc) { break; } } } #define OPT_DST 0x01 #define OPT_SRC 0x02 static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { struct ebt_among_info *amonginfo = (struct ebt_among_info *)(*match)->data; struct ebt_mac_wormhash *wh; switch (c) { case AMONG_DST: case AMONG_SRC: if (c == AMONG_DST) { check_option(flags, OPT_DST); wh = &amonginfo->wh_dst; amonginfo->bitmask |= EBT_AMONG_DST; } else { check_option(flags, OPT_SRC); wh = &amonginfo->wh_src; amonginfo->bitmask |= EBT_AMONG_SRC; } if (optind > argc) print_error("No MAC list specified\n"); fill_wormhash(wh, argv[optind - 1]); break; default: return 0; } return 1; } static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { } static void wormhash_printout(const struct ebt_mac_wormhash *wh) { int i; int offset; for (i = 0; i < 256; i++) { const struct ebt_mac_wormhash_tuple *p; offset = wh->table[i]; while (offset) { p = (const struct ebt_mac_wormhash_tuple*)((const char*)wh + offset); printf("%s,", ether_ntoa((const struct ether_addr *)(((const char*)&p->cmp[0]) + 2))); offset = p->next_ofs; } } printf(" "); } static void print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match) { struct ebt_among_info *amonginfo = (struct ebt_among_info *)match->data; if (amonginfo->bitmask & EBT_AMONG_DST) { printf("--among-dst "); wormhash_printout(&amonginfo->wh_dst); } if (amonginfo->bitmask & EBT_AMONG_SRC) { printf("--among-src "); wormhash_printout(&amonginfo->wh_src); } } static int compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2) { struct ebt_among_info *amonginfo1 = (struct ebt_among_info *)m1->data; struct ebt_among_info *amonginfo2 = (struct ebt_among_info *)m2->data; #ifdef DEBUG // hexdump(amonginfo1, sizeof(struct ebt_among_info)); // hexdump(amonginfo2, sizeof(struct ebt_among_info)); #endif /* DEBUG */ return memcmp(amonginfo1, amonginfo2, sizeof(struct ebt_among_info)) == 0; } static struct ebt_u_match among_match = { EBT_AMONG_MATCH, sizeof(struct ebt_among_info), print_help, init, parse, final_check, print, compare, opts }; static void _init(void) __attribute__ ((constructor)); static void _init(void) { register_match(&among_match); }