summaryrefslogtreecommitdiff
path: root/polux/application/ebtables/extensions/ebt_ip.c
diff options
context:
space:
mode:
Diffstat (limited to 'polux/application/ebtables/extensions/ebt_ip.c')
-rw-r--r--polux/application/ebtables/extensions/ebt_ip.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/polux/application/ebtables/extensions/ebt_ip.c b/polux/application/ebtables/extensions/ebt_ip.c
new file mode 100644
index 0000000000..b836baec88
--- /dev/null
+++ b/polux/application/ebtables/extensions/ebt_ip.c
@@ -0,0 +1,475 @@
+/*
+ * ebtables ebt_ip: IP extension module for userspace
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * Changes:
+ * added ip-sport and ip-dport; parsing of port arguments is
+ * based on code from iptables-1.2.7a
+ * Innominate Security Technologies AG <mhopf@innominate.com>
+ * September, 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <netdb.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_ip.h>
+
+#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'
+#define IP_SPORT '5'
+#define IP_DPORT '6'
+
+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 },
+ { "ip-source-port" , required_argument, 0, IP_SPORT },
+ { "ip-sport" , required_argument, 0, IP_SPORT },
+ { "ip-destination-port" , required_argument, 0, IP_DPORT },
+ { "ip-dport" , required_argument, 0, IP_DPORT },
+ { 0 }
+};
+
+/* put the ip string into 4 bytes */
+static int undot_ip(char *ip, unsigned char *ip2)
+{
+ char *p, *q, *end;
+ long int onebyte;
+ int 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;
+ long int bits;
+ uint32_t 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, uint32_t *addr, uint32_t *msk)
+{
+ char *p;
+
+ /* first the mask */
+ if ((p = strrchr(address, '/')) != NULL) {
+ *p = '\0';
+ if (ip_mask(p + 1, (unsigned char *)msk))
+ print_error("Problem with the IP mask");
+ }
+ else
+ *msk = 0xFFFFFFFF;
+
+ if (undot_ip(address, (unsigned char *)addr))
+ print_error("Problem with the IP address");
+ *addr = *addr & *msk;
+}
+
+/* transform the ip mask into a string ready for output */
+char *mask_to_dotted(uint32_t mask)
+{
+ int i;
+ static char buf[20];
+ uint32_t maskaddr, bits;
+
+ maskaddr = ntohl(mask);
+
+ /* don't print /32 */
+ if (mask == 0xFFFFFFFFL) {
+ *buf = '\0';
+ return buf;
+ }
+
+ 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;
+}
+
+/* transform a protocol and service name into a port number */
+static uint16_t parse_port(const char *protocol, const char *name)
+{
+ struct servent *service;
+ char *end;
+ int port;
+
+ port = strtol(name, &end, 10);
+ if (*end != '\0') {
+ if (protocol &&
+ (service = getservbyname(name, protocol)) != NULL)
+ return ntohs(service->s_port);
+ }
+ else if (port >= 0 || port <= 0xFFFF) {
+ return port;
+ }
+ print_error("Problem with specified %s port '%s'",
+ protocol?protocol:"", name);
+ return 0; /* never reached */
+}
+
+static void
+parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
+{
+ char *buffer;
+ char *cp;
+
+ buffer = strdup(portstring);
+ if ((cp = strchr(buffer, ':')) == NULL)
+ ports[0] = ports[1] = parse_port(protocol, buffer);
+ else {
+ *cp = '\0';
+ cp++;
+ ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0;
+ ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF;
+
+ if (ports[0] > ports[1])
+ print_error("Invalid portrange (min > max)");
+ }
+ free(buffer);
+}
+
+static void print_port_range(uint16_t *ports)
+{
+ if (ports[0] == ports[1])
+ printf("%d ", ports[0]);
+ else
+ printf("%d:%d ", ports[0], ports[1]);
+}
+
+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"
+"--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
+"--ip-dport [!] port[:port] : tcp/udp destination port or port range\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
+#define OPT_SPORT 0x10
+#define OPT_DPORT 0x20
+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;
+ long 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_SPORT:
+ case IP_DPORT:
+ if (c == IP_SPORT) {
+ check_option(flags, OPT_SPORT);
+ ipinfo->bitmask |= EBT_IP_SPORT;
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_SPORT;
+ } else {
+ check_option(flags, OPT_DPORT);
+ ipinfo->bitmask |= EBT_IP_DPORT;
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_DPORT;
+ }
+ if (optind > argc)
+ print_error("Missing port argument");
+ if (c == IP_SPORT)
+ parse_port_range(NULL, argv[optind - 1], ipinfo->sport);
+ else
+ parse_port_range(NULL, argv[optind - 1], ipinfo->dport);
+ 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 || *end != '\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");
+ (unsigned char) i = strtoul(argv[optind - 1], &end, 10);
+ if (*end != '\0') {
+ struct protoent *pe;
+
+ pe = getprotobyname(argv[optind - 1]);
+ if (pe == NULL)
+ print_error
+ ("Unknown specified IP protocol - %s",
+ argv[optind - 1]);
+ ipinfo->protocol = pe->p_proto;
+ } else {
+ ipinfo->protocol = (unsigned char) 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 hookmask, unsigned int time)
+{
+ struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
+
+ if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO)
+ print_error("For IP filtering the protocol must be "
+ "specified as IPv4");
+
+ if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
+ (!(ipinfo->bitmask & EBT_IP_PROTO) ||
+ ipinfo->invflags & EBT_IP_PROTO ||
+ (ipinfo->protocol!=IPPROTO_TCP &&
+ ipinfo->protocol!=IPPROTO_UDP)))
+ print_error("For port filtering the IP protocol must be "
+ "either 6 (tcp) or 17 (udp)");
+}
+
+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("--ip-src ");
+ 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("--ip-dst ");
+ 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) {
+ struct protoent *pe;
+
+ printf("--ip-proto ");
+ if (ipinfo->invflags & EBT_IP_PROTO)
+ printf("! ");
+ pe = getprotobynumber(ipinfo->protocol);
+ if (pe == NULL) {
+ printf("%d ", ipinfo->protocol);
+ } else {
+ printf("%s ", pe->p_name);
+ }
+ }
+ if (ipinfo->bitmask & EBT_IP_SPORT) {
+ printf("--ip-sport ");
+ if (ipinfo->invflags & EBT_IP_SPORT) {
+ printf("! ");
+ }
+ print_port_range(ipinfo->sport);
+ }
+ if (ipinfo->bitmask & EBT_IP_DPORT) {
+ printf("--ip-dport ");
+ if (ipinfo->invflags & EBT_IP_DPORT) {
+ printf("! ");
+ }
+ print_port_range(ipinfo->dport);
+ }
+}
+
+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;
+ }
+ if (ipinfo1->bitmask & EBT_IP_SPORT) {
+ if (ipinfo1->sport[0] != ipinfo2->sport[0] ||
+ ipinfo1->sport[1] != ipinfo2->sport[1])
+ return 0;
+ }
+ if (ipinfo1->bitmask & EBT_IP_DPORT) {
+ if (ipinfo1->dport[0] != ipinfo2->dport[0] ||
+ ipinfo1->dport[1] != ipinfo2->dport[1])
+ return 0;
+ }
+ return 1;
+}
+
+static struct ebt_u_match ip_match =
+{
+ .name = EBT_IP_MATCH,
+ .size = sizeof(struct ebt_ip_info),
+ .help = print_help,
+ .init = init,
+ .parse = parse,
+ .final_check = final_check,
+ .print = print,
+ .compare = compare,
+ .extra_ops = opts,
+};
+
+static void _init(void) __attribute((constructor));
+static void _init(void)
+{
+ register_match(&ip_match);
+}