From 1abc55d3114378b4e73ec315eac6b122e55148c4 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Sat, 1 Jun 2002 19:23:47 +0000 Subject: Initial revision --- extensions/Makefile | 12 ++ extensions/ebt_arp.c | 289 ++++++++++++++++++++++++++++++++++++++++ extensions/ebt_ip.c | 318 ++++++++++++++++++++++++++++++++++++++++++++ extensions/ebt_log.c | 197 +++++++++++++++++++++++++++ extensions/ebt_nat.c | 222 +++++++++++++++++++++++++++++++ extensions/ebt_redirect.c | 109 +++++++++++++++ extensions/ebt_standard.c | 70 ++++++++++ extensions/ebt_vlan.c | 231 ++++++++++++++++++++++++++++++++ extensions/ebtable_broute.c | 25 ++++ extensions/ebtable_filter.c | 32 +++++ extensions/ebtable_nat.c | 32 +++++ 11 files changed, 1537 insertions(+) create mode 100644 extensions/Makefile create mode 100644 extensions/ebt_arp.c create mode 100644 extensions/ebt_ip.c create mode 100644 extensions/ebt_log.c create mode 100644 extensions/ebt_nat.c create mode 100644 extensions/ebt_redirect.c create mode 100644 extensions/ebt_standard.c create mode 100644 extensions/ebt_vlan.c create mode 100644 extensions/ebtable_broute.c create mode 100644 extensions/ebtable_filter.c create mode 100644 extensions/ebtable_nat.c (limited to 'extensions') diff --git a/extensions/Makefile b/extensions/Makefile new file mode 100644 index 0000000..109af35 --- /dev/null +++ b/extensions/Makefile @@ -0,0 +1,12 @@ +#! /usr/bin/make + +EXT_FUNC+=nat arp ip standard log redirect vlan +EXT_TABLES+=filter nat broute +EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/ebt_$(T).o) +EXT_OBJS+=$(foreach T,$(EXT_TABLES), extensions/ebtable_$(T).o) + +extensions/ebt_%.o: extensions/ebt_%.c include/ebtables_u.h + $(CC) $(CFLAGS) -c -o $@ $< +extensions/ebtable_%.o: extensions/ebtable_%.c + $(CC) $(CFLAGS) -c -o $@ $< + diff --git a/extensions/ebt_arp.c b/extensions/ebt_arp.c new file mode 100644 index 0000000..0e22b0b --- /dev/null +++ b/extensions/ebt_arp.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +#define ARP_OPCODE '1' +#define ARP_HTYPE '2' +#define ARP_PTYPE '3' +#define ARP_IP_S '4' +#define ARP_IP_D '5' +static struct option opts[] = +{ + { "arp-opcode" , required_argument, 0, ARP_OPCODE }, + { "arp-op" , required_argument, 0, ARP_OPCODE }, + { "arp-htype" , required_argument, 0, ARP_HTYPE }, + { "arp-ptype" , required_argument, 0, ARP_PTYPE }, + { "arp-ip-src" , required_argument, 0, ARP_IP_S }, + { "arp-ip-dst" , required_argument, 0, ARP_IP_D }, + { 0 } +}; + +// a few names +static char *opcodes[] = +{ + "Request", + "Reply", + "Request Reverse", + "Reply Reverse", + "DRARP Request", + "DRARP Reply", + "DRARP Error", + "InARP Request", + "ARP NAK", + "" +}; + +static void print_help() +{ + int i = 0; + + printf( +"arp options:\n" +"--arp-opcode opcode : ARP opcode (integer or string)\n" +"--arp-htype type : ARP hardware type (integer or string)\n" +"--arp-ptype type : ARP protocol type (hexadecimal or string)\n" +"--arp-ip-src [!] address[/mask]: ARP ip source specification\n" +"--arp-ip-dst [!] address[/mask]: ARP ip target specification\n" +" opcode strings: \n"); + while (strcmp(opcodes[i], "")) { + printf("%d = %s\n", i + 1, opcodes[i]); + i++; + } + printf( +" hardware type string: \n 1 = Ethernet\n" +" protocol type string: \n 0x0800 = IPv4\n"); +} + +static void init(struct ebt_entry_match *match) +{ + struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data; + + arpinfo->invflags = 0; + arpinfo->bitmask = 0; +} + +// defined in ebt_ip.c +void parse_ip_address(char *address, __u32 *addr, __u32 *msk); + +#define OPT_OPCODE 0x01 +#define OPT_HTYPE 0x02 +#define OPT_PTYPE 0x04 +#define OPT_IP_S 0x08 +#define OPT_IP_D 0x10 +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_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data; + int i; + char *end; + __u32 *addr; + __u32 *mask; + + switch (c) { + case ARP_OPCODE: + check_option(flags, OPT_OPCODE); + if (check_inverse(optarg)) + arpinfo->invflags |= EBT_ARP_OPCODE; + + if (optind > argc) + print_error("Missing arp opcode argument"); + i = strtol(argv[optind - 1], &end, 10); + if (i < 0 || i >= (0x1 << 16) || *end !='\0') { + i = 0; + while (strcmp(opcodes[i], "")) { + if (!strcasecmp(opcodes[i], optarg)) + break; + i++; + } + if (!strcmp(opcodes[i], "")) + print_error("Problem with specified " + "arp opcode"); + } + arpinfo->opcode = htons(i); + arpinfo->bitmask |= EBT_ARP_OPCODE; + break; + + case ARP_HTYPE: + check_option(flags, OPT_HTYPE); + if (check_inverse(optarg)) + arpinfo->invflags |= EBT_ARP_HTYPE; + + if (optind > argc) + print_error("Missing arp hardware type argument"); + i = strtol(argv[optind - 1], &end, 10); + if (i < 0 || i >= (0x1 << 16) || *end !='\0') { + if (!strcasecmp("Ethernet", argv[optind - 1])) + i = 1; + else + print_error("Problem with specified arp " + "hardware type"); + } + arpinfo->htype = htons(i); + arpinfo->bitmask |= EBT_ARP_HTYPE; + break; + + case ARP_PTYPE: + check_option(flags, OPT_PTYPE); + if (check_inverse(optarg)) + arpinfo->invflags |= EBT_ARP_PTYPE; + + if (optind > argc) + print_error("Missing arp protocol type argument"); + i = strtol(argv[optind - 1], &end, 16); + if (i < 0 || i >= (0x1 << 16) || *end !='\0') { + if (!strcasecmp("IPv4", argv[optind - 1])) + i = 0x0800; + else + print_error("Problem with specified arp " + "protocol type"); + } + arpinfo->ptype = htons(i); + arpinfo->bitmask |= EBT_ARP_PTYPE; + break; + + case ARP_IP_S: + case ARP_IP_D: + if (c == ARP_IP_S) { + check_option(flags, OPT_IP_S); + addr = &arpinfo->saddr; + mask = &arpinfo->smsk; + arpinfo->bitmask |= EBT_ARP_SRC_IP; + } else { + check_option(flags, OPT_IP_D); + addr = &arpinfo->daddr; + mask = &arpinfo->dmsk; + arpinfo->bitmask |= EBT_ARP_DST_IP; + } + if (check_inverse(optarg)) { + if (c == ARP_IP_S) + arpinfo->invflags |= EBT_ARP_SRC_IP; + else + arpinfo->invflags |= EBT_ARP_DST_IP; + } + if (optind > argc) + print_error("Missing ip address argument"); + parse_ip_address(argv[optind - 1], addr, mask); + 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 hook) +{ + if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 || + (entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP)) + print_error("For (R)ARP filtering the protocol must be " + "specified as ARP or RARP"); +} + +// defined in the ebt_ip.c +char *mask_to_dotted(__u32 mask); +static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_match *match) +{ + struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data; + int i; + + if (arpinfo->bitmask & EBT_ARP_OPCODE) { + printf("arp opcode: "); + if (arpinfo->invflags & EBT_ARP_OPCODE) + printf("! "); + printf("%d ", ntohs(arpinfo->opcode)); + } + if (arpinfo->bitmask & EBT_ARP_HTYPE) { + printf("arp htype: "); + if (arpinfo->invflags & EBT_ARP_HTYPE) + printf("! "); + printf("%d ", ntohs(arpinfo->htype)); + } + if (arpinfo->bitmask & EBT_ARP_PTYPE) { + printf("arp ptype: "); + if (arpinfo->invflags & EBT_ARP_PTYPE) + printf("! "); + printf("0x%x ", ntohs(arpinfo->ptype)); + } + if (arpinfo->bitmask & EBT_ARP_SRC_IP) { + printf("arp src IP "); + if (arpinfo->invflags & EBT_ARP_SRC_IP) + printf("! "); + for (i = 0; i < 4; i++) + printf("%d%s", ((unsigned char *)&arpinfo->saddr)[i], + (i == 3) ? "" : "."); + printf("%s, ", mask_to_dotted(arpinfo->smsk)); + } + if (arpinfo->bitmask & EBT_ARP_DST_IP) { + printf("arp dst IP "); + if (arpinfo->invflags & EBT_ARP_DST_IP) + printf("! "); + for (i = 0; i < 4; i++) + printf("%d%s", ((unsigned char *)&arpinfo->daddr)[i], + (i == 3) ? "" : "."); + printf("%s, ", mask_to_dotted(arpinfo->dmsk)); + } +} + +static int compare(const struct ebt_entry_match *m1, + const struct ebt_entry_match *m2) +{ + struct ebt_arp_info *arpinfo1 = (struct ebt_arp_info *)m1->data; + struct ebt_arp_info *arpinfo2 = (struct ebt_arp_info *)m2->data; + + if (arpinfo1->bitmask != arpinfo2->bitmask) + return 0; + if (arpinfo1->invflags != arpinfo2->invflags) + return 0; + if (arpinfo1->bitmask & EBT_ARP_OPCODE) { + if (arpinfo1->opcode != arpinfo2->opcode) + return 0; + } + if (arpinfo1->bitmask & EBT_ARP_HTYPE) { + if (arpinfo1->htype != arpinfo2->htype) + return 0; + } + if (arpinfo1->bitmask & EBT_ARP_PTYPE) { + if (arpinfo1->ptype != arpinfo2->ptype) + return 0; + } + if (arpinfo1->bitmask & EBT_ARP_SRC_IP) { + if (arpinfo1->saddr != arpinfo2->saddr) + return 0; + if (arpinfo1->smsk != arpinfo2->smsk) + return 0; + } + if (arpinfo1->bitmask & EBT_ARP_DST_IP) { + if (arpinfo1->daddr != arpinfo2->daddr) + return 0; + if (arpinfo1->dmsk != arpinfo2->dmsk) + return 0; + } + return 1; +} + +static struct ebt_u_match arp_match = +{ + EBT_ARP_MATCH, + sizeof(struct ebt_arp_info), + print_help, + init, + parse, + final_check, + print, + compare, + opts, +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_match(&arp_match); +} diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c new file mode 100644 index 0000000..5d62d3a --- /dev/null +++ b/extensions/ebt_ip.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +#define IP_SOURCE '1' +#define IP_DEST '2' +#define IP_myTOS '3' // include/bits/in.h seems to already define IP_TOS +#define IP_PROTO '4' + +static struct option opts[] = +{ + { "ip-source" , required_argument, 0, IP_SOURCE }, + { "ip-src" , required_argument, 0, IP_SOURCE }, + { "ip-destination", required_argument, 0, IP_DEST }, + { "ip-dst" , required_argument, 0, IP_DEST }, + { "ip-tos" , required_argument, 0, IP_myTOS }, + { "ip-protocol" , required_argument, 0, IP_PROTO }, + { "ip-proto" , required_argument, 0, IP_PROTO }, + { 0 } +}; + +// put the ip string into 4 bytes +static int undot_ip(char *ip, unsigned char *ip2) +{ + char *p, *q, *end; + int onebyte, i; + char buf[20]; + + strncpy(buf, ip, sizeof(buf) - 1); + + p = buf; + for (i = 0; i < 3; i++) { + if ((q = strchr(p, '.')) == NULL) + return -1; + *q = '\0'; + onebyte = strtol(p, &end, 10); + if (*end != '\0' || onebyte > 255 || onebyte < 0) + return -1; + ip2[i] = (unsigned char)onebyte; + p = q + 1; + } + + onebyte = strtol(p, &end, 10); + if (*end != '\0' || onebyte >255 || onebyte < 0) + return -1; + ip2[3] = (unsigned char)onebyte; + + return 0; +} + +// put the mask into 4 bytes +static int ip_mask(char *mask, unsigned char *mask2) +{ + char *end; + int bits; + __u32 mask22; + + if (undot_ip(mask, mask2)) { + // not the /a.b.c.e format, maybe the /x format + bits = strtol(mask, &end, 10); + if (*end != '\0' || bits > 32 || bits < 0) + return -1; + if (bits != 0) { + mask22 = htonl(0xFFFFFFFF << (32 - bits)); + memcpy(mask2, &mask22, 4); + } else { + mask22 = 0xFFFFFFFF; + memcpy(mask2, &mask22, 4); + } + } + return 0; +} + +// set the ip mask and ip address +void parse_ip_address(char *address, __u32 *addr, __u32 *msk) +{ + char *p; + int i; + + // first the mask + if ((p = strrchr(address, '/')) != NULL) { + *p = '\0'; + i = ip_mask(p + 1, (unsigned char *)msk); + if (i) + print_error("Problem with the ip mask"); + } + else + *msk = 0xFFFFFFFF; + + i = undot_ip(address, (unsigned char *)addr); + if (i) + print_error("Problem with the ip address"); + *addr = *addr & *msk; +} + +// transform the ip mask into a string ready for output +char *mask_to_dotted(__u32 mask) +{ + int i; + static char buf[20]; + __u32 maskaddr, bits; + + maskaddr = ntohl(mask); + + // don't print /32 + if (mask == 0xFFFFFFFFL) + return ""; + + i = 32; + bits = 0xFFFFFFFEL; // case 0xFFFFFFFF has just been dealt with + while (--i >= 0 && maskaddr != bits) + bits <<= 1; + + if (i > 0) + sprintf(buf, "/%d", i); + else if (!i) + *buf = '\0'; + else + // mask was not a decent combination of 1's and 0's + sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0], + ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2], + ((unsigned char *)&mask)[3]); + + return buf; +} + +static void print_help() +{ + printf( +"ip options:\n" +"--ip-src [!] address[/mask]: ip source specification\n" +"--ip-dst [!] address[/mask]: ip destination specification\n" +"--ip-tos [!] tos : ip tos specification\n" +"--ip-proto [!] protocol : ip protocol specification\n"); +} + +static void init(struct ebt_entry_match *match) +{ + struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; + + ipinfo->invflags = 0; + ipinfo->bitmask = 0; +} + +#define OPT_SOURCE 0x01 +#define OPT_DEST 0x02 +#define OPT_TOS 0x04 +#define OPT_PROTO 0x08 +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_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data; + char *end, *buffer; + int i; + + switch (c) { + case IP_SOURCE: + check_option(flags, OPT_SOURCE); + ipinfo->bitmask |= EBT_IP_SOURCE; + + case IP_DEST: + if (c == IP_DEST) { + check_option(flags, OPT_DEST); + ipinfo->bitmask |= EBT_IP_DEST; + } + if (check_inverse(optarg)) { + if (c == IP_SOURCE) + ipinfo->invflags |= EBT_IP_SOURCE; + else + ipinfo->invflags |= EBT_IP_DEST; + } + + if (optind > argc) + print_error("Missing ip address argument"); + if (c == IP_SOURCE) + parse_ip_address(argv[optind - 1], &ipinfo->saddr, + &ipinfo->smsk); + else + parse_ip_address(argv[optind - 1], &ipinfo->daddr, + &ipinfo->dmsk); + break; + + case IP_myTOS: + check_option(flags, OPT_TOS); + if (check_inverse(optarg)) + ipinfo->invflags |= EBT_IP_TOS; + + if (optind > argc) + print_error("Missing ip tos argument"); + i = strtol(argv[optind - 1], &end, 16); + if (i < 0 || i > 255 || *buffer != '\0') + print_error("Problem with specified ip tos"); + ipinfo->tos = i; + ipinfo->bitmask |= EBT_IP_TOS; + break; + + case IP_PROTO: + check_option(flags, OPT_PROTO); + if (check_inverse(optarg)) + ipinfo->invflags |= EBT_IP_PROTO; + if (optind > argc) + print_error("Missing ip protocol argument"); + i = strtol(argv[optind - 1], &end, 10); + if (i < 0 || i > 255 || *end != '\0') + print_error("Problem with specified ip protocol"); + ipinfo->protocol = i; + ipinfo->bitmask |= EBT_IP_PROTO; + 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 hook) +{ + if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 || + entry->ethproto != ETH_P_IP) + print_error("For IP filtering the protocol must be " + "specified as IPv4"); +} + +static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_match *match) +{ + struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; + int j; + + if (ipinfo->bitmask & EBT_IP_SOURCE) { + printf("source ip: "); + if (ipinfo->invflags & EBT_IP_SOURCE) + printf("! "); + for (j = 0; j < 4; j++) + printf("%d%s",((unsigned char *)&ipinfo->saddr)[j], + (j == 3) ? "" : "."); + printf("%s, ", mask_to_dotted(ipinfo->smsk)); + } + if (ipinfo->bitmask & EBT_IP_DEST) { + printf("dest ip: "); + if (ipinfo->invflags & EBT_IP_DEST) + printf("! "); + for (j = 0; j < 4; j++) + printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j], + (j == 3) ? "" : "."); + printf("%s, ", mask_to_dotted(ipinfo->dmsk)); + } + if (ipinfo->bitmask & EBT_IP_TOS) { + printf("ip TOS: "); + if (ipinfo->invflags & EBT_IP_TOS) + printf("! "); + printf("0x%02X, ", ipinfo->tos); + } + if (ipinfo->bitmask & EBT_IP_PROTO) { + printf("ip proto: "); + if (ipinfo->invflags & EBT_IP_DEST) + printf("! "); + printf("%d, ", ipinfo->protocol); + } +} + +static int compare(const struct ebt_entry_match *m1, + const struct ebt_entry_match *m2) +{ + struct ebt_ip_info *ipinfo1 = (struct ebt_ip_info *)m1->data; + struct ebt_ip_info *ipinfo2 = (struct ebt_ip_info *)m2->data; + + if (ipinfo1->bitmask != ipinfo2->bitmask) + return 0; + if (ipinfo1->invflags != ipinfo2->invflags) + return 0; + if (ipinfo1->bitmask & EBT_IP_SOURCE) { + if (ipinfo1->saddr != ipinfo2->saddr) + return 0; + if (ipinfo1->smsk != ipinfo2->smsk) + return 0; + } + if (ipinfo1->bitmask & EBT_IP_DEST) { + if (ipinfo1->daddr != ipinfo2->daddr) + return 0; + if (ipinfo1->dmsk != ipinfo2->dmsk) + return 0; + } + if (ipinfo1->bitmask & EBT_IP_TOS) { + if (ipinfo1->tos != ipinfo2->tos) + return 0; + } + if (ipinfo1->bitmask & EBT_IP_PROTO) { + if (ipinfo1->protocol != ipinfo2->protocol) + return 0; + } + return 1; +} + +static struct ebt_u_match ip_match = +{ + EBT_IP_MATCH, + sizeof(struct ebt_ip_info), + print_help, + init, + parse, + final_check, + print, + compare, + opts, +}; + +static void _init(void) __attribute((constructor)); +static void _init(void) +{ + register_match(&ip_match); +} diff --git a/extensions/ebt_log.c b/extensions/ebt_log.c new file mode 100644 index 0000000..6dff952 --- /dev/null +++ b/extensions/ebt_log.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +// copied from syslog.h +// used for the LOG target +#define LOG_EMERG 0 // system is unusable +#define LOG_ALERT 1 // action must be taken immediately +#define LOG_CRIT 2 // critical conditions +#define LOG_ERR 3 // error conditions +#define LOG_WARNING 4 // warning conditions +#define LOG_NOTICE 5 // normal but significant condition +#define LOG_INFO 6 // informational +#define LOG_DEBUG 7 // debug-level messages +#define LOG_DEFAULT_LEVEL LOG_INFO + +typedef struct _code { + char *c_name; + int c_val; +} CODE; + +static CODE eight_priority[] = { + { "emerg", LOG_EMERG }, + { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "error", LOG_ERR }, + { "warning", LOG_WARNING }, + { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, + { "debug", LOG_DEBUG }, + { NULL, -1 } +}; + +static int name_to_loglevel(char* arg) +{ + int i = 0, c_val = eight_priority[0].c_val; + + while (c_val != -1) { + if (!strcmp(arg, eight_priority[i].c_name)) + return c_val; + i++; + c_val = eight_priority[i].c_val; + } + // return bad loglevel + return 9; +} + +#define LOG_PREFIX '1' +#define LOG_LEVEL '2' +#define LOG_ARP '3' +#define LOG_IP '4' +#define LOG_LOG '5' +static struct option opts[] = +{ + { "log-prefix", required_argument, 0, LOG_PREFIX }, + { "log-level" , required_argument, 0, LOG_LEVEL }, + { "log-arp" , no_argument , 0, LOG_ARP }, + { "log-ip" , no_argument , 0, LOG_IP }, + { "log" , no_argument , 0, LOG_LOG }, + { 0 } +}; + +static void print_help() +{ + int i; + + printf( +"log options:\n" +"--log : use this if you're not specifying anything\n" +"--log-level level : level = [1-8] or a string\n" +"--log-prefix prefix : max. %d chars.\n" +"--log-ip : put ip info. in the log for ip packets\n" +"--log-arp : put (r)arp info. in the log for (r)arp packets\n" + , EBT_LOG_PREFIX_SIZE - 1); + printf("levels:\n"); + for (i = 0; i < 8; i++) + printf("%d = %s\n", eight_priority[i].c_val, + eight_priority[i].c_name); +} + +static void init(struct ebt_entry_watcher *watcher) +{ + struct ebt_log_info *loginfo = (struct ebt_log_info *)watcher->data; + + loginfo->bitmask = 0; + loginfo->prefix[0] = '\0'; + loginfo->loglevel = LOG_NOTICE; +} + +#define OPT_PREFIX 0x01 +#define OPT_LEVEL 0x02 +#define OPT_ARP 0x04 +#define OPT_IP 0x08 +#define OPT_LOG 0x10 +static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, + unsigned int *flags, struct ebt_entry_watcher **watcher) +{ + struct ebt_log_info *loginfo = (struct ebt_log_info *)(*watcher)->data; + int i; + char *end; + + switch (c) { + case LOG_PREFIX: + check_option(flags, OPT_PREFIX); + if (strlen(optarg) > sizeof(loginfo->prefix) - 1) + print_error("Prefix too long"); + strcpy(loginfo->prefix, optarg); + break; + + case LOG_LEVEL: + check_option(flags, OPT_LEVEL); + i = strtol(optarg, &end, 16); + if (*end != '\0' || i < 0 || i > 7) + loginfo->loglevel = name_to_loglevel(optarg); + else + loginfo->loglevel = i; + if (loginfo->loglevel == 9) + print_error("Problem with the log-level"); + break; + + case LOG_IP: + check_option(flags, OPT_IP); + loginfo->bitmask |= EBT_LOG_IP; + break; + + case LOG_ARP: + check_option(flags, OPT_ARP); + loginfo->bitmask |= EBT_LOG_ARP; + break; + + case LOG_LOG: + check_option(flags, OPT_LOG); + break; + default: + return 0; + } + return 1; +} + +static void final_check(const struct ebt_u_entry *entry, + const struct ebt_entry_watcher *watcher, const char *name, unsigned int hook) +{ + return; +} + +static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_watcher *watcher) +{ + struct ebt_log_info *loginfo = (struct ebt_log_info *)watcher->data; + + printf("log: log-level = %s - log-prefix = \"%s\"", + eight_priority[loginfo->loglevel].c_name, + loginfo->prefix); + if (loginfo->bitmask & EBT_LOG_IP) + printf(" - log-ip"); + if (loginfo->bitmask & EBT_LOG_ARP) + printf(" - log-arp"); + printf(" "); +} + +static int compare(const struct ebt_entry_watcher *w1, + const struct ebt_entry_watcher *w2) +{ + struct ebt_log_info *loginfo1 = (struct ebt_log_info *)w1->data; + struct ebt_log_info *loginfo2 = (struct ebt_log_info *)w2->data; + + if (loginfo1->loglevel != loginfo2->loglevel) + return 0; + if (loginfo1->bitmask != loginfo2->bitmask) + return 0; + return !strcmp(loginfo1->prefix, loginfo2->prefix); +} + +static struct ebt_u_watcher log_watcher = +{ + EBT_LOG_WATCHER, + sizeof(struct ebt_log_info), + print_help, + init, + parse, + final_check, + print, + compare, + opts, +}; + +#undef _init +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_watcher(&log_watcher); +} diff --git a/extensions/ebt_nat.c b/extensions/ebt_nat.c new file mode 100644 index 0000000..dbdb5a4 --- /dev/null +++ b/extensions/ebt_nat.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +extern char *standard_targets[NUM_STANDARD_TARGETS]; + +int to_source_supplied, to_dest_supplied; + +#define NAT_S '1' +#define NAT_D '1' +#define NAT_S_TARGET '2' +#define NAT_D_TARGET '2' +static struct option opts_s[] = +{ + { "to-source" , required_argument, 0, NAT_S }, + { "to-src" , required_argument, 0, NAT_S }, + { "snat-target" , required_argument, 0, NAT_S_TARGET }, + { 0 } +}; + +static struct option opts_d[] = +{ + { "to-destination", required_argument, 0, NAT_D }, + { "to-dst" , required_argument, 0, NAT_D }, + { "dnat-target" , required_argument, 0, NAT_D_TARGET }, + { 0 } +}; + +static void print_help_s() +{ + printf( + "snat options:\n" + " --to-src address : MAC address to map source to\n" + " --snat-target target : ACCEPT, DROP or CONTINUE\n"); +} + +static void print_help_d() +{ + printf( + "dnat options:\n" + " --to-dst address : MAC address to map destination to\n" + " --dnat-target target : ACCEPT, DROP or CONTINUE\n"); +} + +static void init_s(struct ebt_entry_target *target) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; + + to_source_supplied = 0; + natinfo->target = EBT_ACCEPT; + return; +} + +static void init_d(struct ebt_entry_target *target) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; + + to_dest_supplied = 0; + natinfo->target = EBT_ACCEPT; + return; +} + +#define OPT_SNAT 0x01 +#define OPT_SNAT_TARGET 0x02 +static int parse_s(int c, char **argv, int argc, + const struct ebt_u_entry *entry, unsigned int *flags, + struct ebt_entry_target **target) +{ + int i; + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data; + + switch (c) { + case NAT_S: + check_option(flags, OPT_SNAT); + to_source_supplied = 1; + if (getmac(optarg, natinfo->mac)) + print_error("Problem with specified to-source mac"); + break; + case NAT_S_TARGET: + check_option(flags, OPT_SNAT_TARGET); + for (i = 0; i < NUM_STANDARD_TARGETS; i++) + if (!strcmp(optarg, standard_targets[i])) { + natinfo->target = i; + break; + } + if (i == NUM_STANDARD_TARGETS) + print_error("Illegal --snat-target target"); + break; + default: + return 0; + } + return 1; +} + +#define OPT_DNAT 0x01 +#define OPT_DNAT_TARGET 0x02 +static int parse_d(int c, char **argv, int argc, + const struct ebt_u_entry *entry, unsigned int *flags, + struct ebt_entry_target **target) +{ + int i; + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data; + + switch (c) { + case NAT_D: + check_option(flags, OPT_DNAT); + to_dest_supplied = 1; + if (getmac(optarg, natinfo->mac)) + print_error("Problem with specified " + "to-destination mac"); + break; + case NAT_D_TARGET: + check_option(flags, OPT_DNAT_TARGET); + for (i = 0; i < NUM_STANDARD_TARGETS; i++) + if (!strcmp(optarg, standard_targets[i])) { + natinfo->target = i; + break; + } + if (i == NUM_STANDARD_TARGETS) + print_error("Illegal --dnat-target target"); + break; + default: + return 0; + } + return 1; +} + +static void final_check_s(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target, const char *name, unsigned int hook) +{ + if (hook != NF_BR_POST_ROUTING || strcmp(name, "nat")) + print_error("Wrong chain for snat"); + if (to_source_supplied == 0) + print_error("No snat address supplied"); +} + +static void final_check_d(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target, const char *name, unsigned int hook) +{ + if ( ((hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) || + strcmp(name, "nat")) && + (hook != NF_BR_BROUTING || strcmp(name, "broute")) ) + print_error("Wrong chain for dnat"); + if (to_dest_supplied == 0) + print_error("No dnat address supplied"); +} + +static void print_s(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; + int i; + + printf("snat - to: "); + for (i = 0; i < ETH_ALEN; i++) + printf("%02x%s", + natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":"); + printf(" --snat-target %s", standard_targets[natinfo->target]); +} + +static void print_d(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target) +{ + struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; + int i; + + printf("dnat - to: "); + for (i = 0; i < ETH_ALEN; i++) + printf("%02x%s", + natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":"); + printf(" --dnat-target %s", standard_targets[natinfo->target]); +} + +static int compare(const struct ebt_entry_target *t1, + const struct ebt_entry_target *t2) +{ + struct ebt_nat_info *natinfo1 = (struct ebt_nat_info *)t1->data; + struct ebt_nat_info *natinfo2 = (struct ebt_nat_info *)t2->data; + + + return !memcmp(natinfo1->mac, natinfo2->mac, sizeof(natinfo1->mac)) && + natinfo1->target == natinfo2->target; +} + +static struct ebt_u_target snat_target = +{ + EBT_SNAT_TARGET, + sizeof(struct ebt_nat_info), + print_help_s, + init_s, + parse_s, + final_check_s, + print_s, + compare, + opts_s, +}; + +static struct ebt_u_target dnat_target = +{ + EBT_DNAT_TARGET, + sizeof(struct ebt_nat_info), + print_help_d, + init_d, + parse_d, + final_check_d, + print_d, + compare, + opts_d, +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_target(&snat_target); + register_target(&dnat_target); +} diff --git a/extensions/ebt_redirect.c b/extensions/ebt_redirect.c new file mode 100644 index 0000000..3dff790 --- /dev/null +++ b/extensions/ebt_redirect.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +extern char *standard_targets[NUM_STANDARD_TARGETS]; + +#define REDIRECT_TARGET '1' +static struct option opts[] = +{ + { "redirect-target" , required_argument, 0, REDIRECT_TARGET }, + { 0 } +}; + +static void print_help() +{ + printf( + "redirect option:\n" + " --redirect-target target : ACCEPT, DROP or CONTINUE\n"); +} + +static void init(struct ebt_entry_target *target) +{ + struct ebt_redirect_info *redirectinfo = + (struct ebt_redirect_info *)target->data; + + redirectinfo->target = EBT_ACCEPT; + return; +} + + +#define OPT_REDIRECT_TARGET 0x01 +static int parse(int c, char **argv, int argc, + const struct ebt_u_entry *entry, unsigned int *flags, + struct ebt_entry_target **target) +{ + int i; + struct ebt_redirect_info *redirectinfo = + (struct ebt_redirect_info *)(*target)->data; + + switch (c) { + case REDIRECT_TARGET: + check_option(flags, OPT_REDIRECT_TARGET); + for (i = 0; i < NUM_STANDARD_TARGETS; i++) + if (!strcmp(optarg, standard_targets[i])) { + redirectinfo->target = i; + break; + } + if (i == NUM_STANDARD_TARGETS) + print_error("Illegal --redirect-target target"); + break; + default: + return 0; + } + return 1; +} + +static void final_check(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target, const char *name, unsigned int hook) +{ + if ( (hook != NF_BR_PRE_ROUTING || strcmp(name, "nat")) && + (hook != NF_BR_BROUTING || strcmp(name, "broute")) ) + print_error("Wrong chain for redirect"); +} + +static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target) +{ + struct ebt_redirect_info *redirectinfo = + (struct ebt_redirect_info *)target->data; + + printf("redirect"); + printf(" --redirect-target %s", standard_targets[redirectinfo->target]); +} + +static int compare(const struct ebt_entry_target *t1, + const struct ebt_entry_target *t2) +{ + struct ebt_redirect_info *redirectinfo1 = + (struct ebt_redirect_info *)t1->data; + struct ebt_redirect_info *redirectinfo2 = + (struct ebt_redirect_info *)t2->data; + + return redirectinfo1->target == redirectinfo2->target; +} + +static struct ebt_u_target redirect_target = +{ + EBT_REDIRECT_TARGET, + sizeof(struct ebt_redirect_info), + print_help, + init, + parse, + final_check, + print, + compare, + opts, +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_target(&redirect_target); +} diff --git a/extensions/ebt_standard.c b/extensions/ebt_standard.c new file mode 100644 index 0000000..983d055 --- /dev/null +++ b/extensions/ebt_standard.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include "../include/ebtables_u.h" + +static struct option opts[] = +{ + {0} +}; + +static void print_help() +{ + printf("Standard targets: DROP, ACCEPT and CONTINUE\n"); +} + +static void init(struct ebt_entry_target *t) +{ + ((struct ebt_standard_target *)t)->verdict = EBT_CONTINUE; +} + +static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, + unsigned int *flags, struct ebt_entry_target **target) +{ + return 0; +} + +static void final_check(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target, const char *name, unsigned int hook) +{ +} + +static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_target *target) +{ + __u8 verdict = ((struct ebt_standard_target *)target)->verdict; + + if (verdict == EBT_CONTINUE) + printf("Continue "); + else if (verdict == EBT_ACCEPT) + printf("Accept "); + else + printf("Drop "); +} + +static int compare(const struct ebt_entry_target *t1, + const struct ebt_entry_target *t2) +{ + return ((struct ebt_standard_target *)t1)->verdict == + ((struct ebt_standard_target *)t2)->verdict; +} + +static struct ebt_u_target standard = +{ + EBT_STANDARD_TARGET, + sizeof(struct ebt_standard_target) - sizeof(struct ebt_entry_target), + print_help, + init, + parse, + final_check, + print, + compare, + opts +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_target(&standard); +} diff --git a/extensions/ebt_vlan.c b/extensions/ebt_vlan.c new file mode 100644 index 0000000..ad3e6f7 --- /dev/null +++ b/extensions/ebt_vlan.c @@ -0,0 +1,231 @@ +/* + * Summary: ebt_vlan userspace module + * + * Description: 802.1Q Virtual LAN match support module for ebtables project. + * Enable to match 802.1Q VLAN tagged frames by VLAN numeric + * identifier (12-bites field) and frame priority (3-bites field) + * + * Authors: + * Bart De Schuymer + * Nick Fedchik + * + * May, 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +#define VLAN_ID '1' +#define VLAN_PRIO '2' + +static struct option opts[] = { + {"vlan-id", required_argument, 0, VLAN_ID}, + {"vlan-prio", required_argument, 0, VLAN_PRIO}, + {0} +}; + +/* + * Print out help for ebtables -h vlan + */ +static void print_help () +{ + printf ("802.1Q VLAN options:\n" + "--vlan-id [!] id : VLAN ID 1-4095 (integer)\n" + "--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n"); +} + +/* + * Initialization function + */ +static void init (struct ebt_entry_match *match) +{ + struct ebt_vlan_info *vlaninfo = + (struct ebt_vlan_info *) match->data; + /* + * Just clean initial values + */ + vlaninfo->id = 0; + vlaninfo->prio = 0; + vlaninfo->invflags = 0; + vlaninfo->bitmask = 0; +} + +#define OPT_VLAN_ID 0x01 +#define OPT_VLAN_PRIO 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_vlan_info *vlaninfo = + (struct ebt_vlan_info *) (*match)->data; + unsigned short i; + char *end; + + switch (c) { + case VLAN_ID: + check_option (flags, OPT_VLAN_ID); + /* + * Check If we got inversed arg for VID, + * otherwise unset inversion flag + */ + if (check_inverse (optarg)) + vlaninfo->invflags |= EBT_VLAN_ID; + /* + * Check arg value presense + */ + if (optind > argc) + print_error ("Missing VLAN ID argument\n"); + /* + * Convert argv to long int, + * set *end to end of argv string, + * base set 10 for decimal only + */ + (unsigned short) i = strtol (argv[optind - 1], &end, 10); + /* + * Check arg val range + */ + if (i < 1 || i >= 4096 || *end != '\0') { + i = 0; + print_error + ("Problem with specified VLAN ID range\n"); + } + vlaninfo->id = i; + vlaninfo->bitmask|=EBT_VLAN_ID; + break; + + case VLAN_PRIO: + check_option (flags, OPT_VLAN_PRIO); + if (check_inverse (optarg)) + vlaninfo->invflags |= EBT_VLAN_PRIO; + if (optind > argc) + print_error + ("Missing VLAN Priority level argument\n"); + /* + * Convert argv to long int, + * set *end to end of argv string, + * base set 10 for decimal only + */ + (unsigned short) i = strtol (argv[optind - 1], &end, 10); + /* + * Check arg val range + */ + if (i >= 8 || *end != '\0') { + i = 0; + print_error + ("Problem with specified VLAN Priority range\n"); + } + vlaninfo->prio = i; + vlaninfo->bitmask|=EBT_VLAN_PRIO; + break; + + default: + return 0; + } + return 1; +} + +/* + * Final check + */ +static void +final_check (const struct ebt_u_entry *entry, + const struct ebt_entry_match *match, + const char *name, unsigned int hook) +{ + /* + * Is any proto supplied there? Or specified proto isn't 802.1Q? + */ + if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q) + print_error + ("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n"); +} + +/* + * Print line when listing rules by ebtables -L + */ +static void +print (const struct ebt_u_entry *entry, + const struct ebt_entry_match *match) +{ + struct ebt_vlan_info *vlaninfo = + (struct ebt_vlan_info *) match->data; + + /* + * Print VLAN ID if they are specified + */ + if (vlaninfo->bitmask & EBT_VLAN_ID) { + printf ("vlan id: %s%d, ", + vlaninfo->invflags & EBT_VLAN_ID ? "!" : "", + vlaninfo->id); + } + /* + * Print VLAN priority if they are specified + */ + if (vlaninfo->bitmask & EBT_VLAN_PRIO) { + printf ("vlan prio: %s%d, ", + vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "", + vlaninfo->prio); + } +} + + +static int +compare (const struct ebt_entry_match *vlan1, + const struct ebt_entry_match *vlan2) +{ + struct ebt_vlan_info *vlaninfo1 = + (struct ebt_vlan_info *) vlan1->data; + struct ebt_vlan_info *vlaninfo2 = + (struct ebt_vlan_info *) vlan2->data; + /* + * Compare argc + */ + if (vlaninfo1->bitmask != vlaninfo2->bitmask) + return 0; + /* + * Compare inv flags + */ + if (vlaninfo1->invflags != vlaninfo2->invflags) + return 0; + /* + * Compare VLAN ID if they are present + */ + if (vlaninfo1->bitmask & EBT_VLAN_ID) { + if (vlaninfo1->id != vlaninfo2->id) + return 0; + }; + /* + * Compare VLAN Prio if they are present + */ + if (vlaninfo1->bitmask & EBT_VLAN_PRIO) { + if (vlaninfo1->prio != vlaninfo2->prio) + return 0; + }; + return 1; +} + +static struct ebt_u_match vlan_match = { + EBT_VLAN_MATCH, + sizeof (struct ebt_vlan_info), + print_help, + init, + parse, + final_check, + print, + compare, + opts, +}; + +static void _init (void) __attribute__ ((constructor)); +static void _init (void) +{ + register_match (&vlan_match); +} diff --git a/extensions/ebtable_broute.c b/extensions/ebtable_broute.c new file mode 100644 index 0000000..2abfcb6 --- /dev/null +++ b/extensions/ebtable_broute.c @@ -0,0 +1,25 @@ +#include +#include +#include "../include/ebtables_u.h" + + +static void print_help(char **hn) +{ + printf("Supported chain for the nat table:\n"); + printf("%s\n",hn[NF_BR_BROUTING]); +} + +static struct +ebt_u_table table = +{ + "broute", + NULL, + print_help, + NULL +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_table(&table); +} diff --git a/extensions/ebtable_filter.c b/extensions/ebtable_filter.c new file mode 100644 index 0000000..cf26983 --- /dev/null +++ b/extensions/ebtable_filter.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include "../include/ebtables_u.h" + +#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ + (1 << NF_BR_LOCAL_OUT)) + +static void print_help(char **hn) +{ + int i; + + printf("Supported chains for the filter table:\n"); + for (i = 0; i < NF_BR_NUMHOOKS; i++) + if (FILTER_VALID_HOOKS & (1 << i)) + printf("%s ", hn[i]); + printf("\n"); +} + +static struct ebt_u_table table = +{ + "filter", + NULL, + print_help, + NULL +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_table(&table); +} diff --git a/extensions/ebtable_nat.c b/extensions/ebtable_nat.c new file mode 100644 index 0000000..4b4ca48 --- /dev/null +++ b/extensions/ebtable_nat.c @@ -0,0 +1,32 @@ +#include +#include +#include "../include/ebtables_u.h" + +#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ + (1 << NF_BR_POST_ROUTING)) + +static void print_help(char **hn) +{ + int i; + + printf("Supported chains for the nat table:\n"); + for (i = 0; i < NF_BR_NUMHOOKS; i++) + if (NAT_VALID_HOOKS & (1 << i)) + printf("%s ", hn[i]); + printf("\n"); +} + +static struct +ebt_u_table table = +{ + "nat", + NULL, + print_help, + NULL +}; + +static void _init(void) __attribute__ ((constructor)); +static void _init(void) +{ + register_table(&table); +} -- cgit v1.2.3