From 07d13c6f31c75ee8ce8dc2e509a890f5dec0f299 Mon Sep 17 00:00:00 2001 From: laforge Date: Fri, 16 Feb 2001 15:19:51 +0000 Subject: Port of IPv6 owner match, fixes for IPv6 limit mac and multiport matches (Jan Rekorajski) --- extensions/.owner-test6 | 2 + extensions/libip6t_limit.c | 198 +++++++++++++++++++++++++++++++ extensions/libip6t_mac.c | 145 +++++++++++++++++++++++ extensions/libip6t_multiport.c | 263 +++++++++++++++++++++++++++++++++++++++++ extensions/libip6t_owner.c | 220 ++++++++++++++++++++++++++++++++++ 5 files changed, 828 insertions(+) create mode 100755 extensions/.owner-test6 create mode 100644 extensions/libip6t_limit.c create mode 100644 extensions/libip6t_mac.c create mode 100644 extensions/libip6t_multiport.c create mode 100644 extensions/libip6t_owner.c (limited to 'extensions') diff --git a/extensions/.owner-test6 b/extensions/.owner-test6 new file mode 100755 index 0000000..9d46e2b --- /dev/null +++ b/extensions/.owner-test6 @@ -0,0 +1,2 @@ +#! /bin/sh +[ -f $KERNEL_DIR/include/linux/netfilter_ipv6/ip6t_owner.h ] && echo owner limit mac multiport diff --git a/extensions/libip6t_limit.c b/extensions/libip6t_limit.c new file mode 100644 index 0000000..3b0318b --- /dev/null +++ b/extensions/libip6t_limit.c @@ -0,0 +1,198 @@ +/* Shared library add-on to iptables to add limit support. + * + * Jérôme de Vivie + * Hervé Eychenne + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define IP6T_LIMIT_AVG "3/hour" +#define IP6T_LIMIT_BURST 5 + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"limit v%s options:\n" +"--limit avg max average match rate: default "IP6T_LIMIT_AVG"\n" +" [Packets per second unless followed by \n" +" /sec /minute /hour /day postfixes]\n" +"--limit-burst number number to match in a burst, default %u\n" +"\n", NETFILTER_VERSION, IP6T_LIMIT_BURST); +} + +static struct option opts[] = { + { "limit", 1, 0, '%' }, + { "limit-burst", 1, 0, '$' }, + { 0 } +}; + +static +int parse_rate(const char *rate, u_int32_t *val) +{ + const char *delim; + u_int32_t r; + u_int32_t mult = 1; /* Seconds by default. */ + + delim = strchr(rate, '/'); + if (delim) { + if (strlen(delim+1) == 0) + return 0; + + if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) + mult = 1; + else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) + mult = 60; + else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) + mult = 60*60; + else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) + mult = 24*60*60; + else + return 0; + } + r = atoi(rate); + if (!r) + return 0; + + /* This would get mapped to infinite (1/day is minimum they + can specify, so we're ok at that end). */ + if (r / mult > IP6T_LIMIT_SCALE) + exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate); + + *val = IP6T_LIMIT_SCALE * mult / r; + return 1; +} + +/* Initialize the match. */ +static void +init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)m->data; + + parse_rate(IP6T_LIMIT_AVG, &r->avg); + r->burst = IP6T_LIMIT_BURST; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +/* FIXME: handle overflow: + if (r->avg*r->burst/r->burst != r->avg) + exit_error(PARAMETER_PROBLEM, + "Sorry: burst too large for that avg rate.\n"); +*/ + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)(*match)->data; + int num; + + switch(c) { + case '%': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --limit"); + if (!parse_rate(optarg, &r->avg)) + exit_error(PARAMETER_PROBLEM, + "bad rate `%s'", optarg); + break; + + case '$': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --limit-burst"); + + num = string_to_number(optarg, 0, 10000); + if (num <= 0) + exit_error(PARAMETER_PROBLEM, + "bad --limit-burst `%s'", optarg); + r->burst = num; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; nothing. */ +static void final_check(unsigned int flags) +{ +} + +static struct rates +{ + const char *name; + u_int32_t mult; +} rates[] = { { "day", IP6T_LIMIT_SCALE*24*60*60 }, + { "hour", IP6T_LIMIT_SCALE*60*60 }, + { "min", IP6T_LIMIT_SCALE*60 }, + { "sec", IP6T_LIMIT_SCALE } }; + +static void print_rate(u_int32_t period) +{ + unsigned int i; + + for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) { + if (period > rates[i].mult + || rates[i].mult % period != 0) + break; + } + + printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)match->data; + printf("limit: avg "); print_rate(r->avg); + printf("burst %u ", r->burst); +} + +/* FIXME: Make minimalist: only print rate if not default --RR */ +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)match->data; + + printf("--limit "); print_rate(r->avg); + if (r->burst != IP6T_LIMIT_BURST) + printf("--limit-burst %u ", r->burst); +} + +struct ip6tables_match limit += { NULL, + "limit", + NETFILTER_VERSION, + IP6T_ALIGN(sizeof(struct ip6t_rateinfo)), + offsetof(struct ip6t_rateinfo, prev), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match6(&limit); +} diff --git a/extensions/libip6t_mac.c b/extensions/libip6t_mac.c new file mode 100644 index 0000000..283c486 --- /dev/null +++ b/extensions/libip6t_mac.c @@ -0,0 +1,145 @@ +/* Shared library add-on to iptables to add MAC address support. */ +#include +#include +#include +#include +#include +#if defined(__GLIBC__) && __GLIBC__ == 2 +#include +#else +#include +#endif +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"MAC v%s options:\n" +" --mac-source [!] XX:XX:XX:XX:XX:XX\n" +" Match source MAC address\n" +"\n", NETFILTER_VERSION); +} + +static struct option opts[] = { + { "mac-source", 1, 0, '1' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +static void +parse_mac(const char *mac, struct ip6t_mac_info *info) +{ + unsigned int i = 0; + + if (strlen(mac) != ETH_ALEN*3-1) + exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac); + + for (i = 0; i < ETH_ALEN; i++) { + long number; + char *end; + + number = strtol(mac + i*3, &end, 16); + + if (end == mac + i*3 + 2 + && number >= 0 + && number <= 255) + info->srcaddr[i] = number; + else + exit_error(PARAMETER_PROBLEM, + "Bad mac address `%s'", mac); + } +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_mac_info *macinfo = (struct ip6t_mac_info *)(*match)->data; + + switch (c) { + case '1': + if (check_inverse(optarg, &invert)) + optind++; + parse_mac(argv[optind-1], macinfo); + if (invert) + macinfo->invert = 1; + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +static void print_mac(unsigned char macaddress[ETH_ALEN], int invert) +{ + unsigned int i; + + printf("%s%02X", invert ? "!" : "", macaddress[0]); + for (i = 1; i < ETH_ALEN; i++) + printf(":%02X", macaddress[i]); + printf(" "); +} + +/* Final check; must have specified --mac. */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "You must specify `--mac-source'"); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + printf("MAC "); + print_mac(((struct ip6t_mac_info *)match->data)->srcaddr, + ((struct ip6t_mac_info *)match->data)->invert); +} + +/* Saves the union ip6t_matchinfo in parsable form to stdout. */ +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + printf("--mac "); + print_mac(((struct ip6t_mac_info *)match->data)->srcaddr, + ((struct ip6t_mac_info *)match->data)->invert); +} + +struct ip6tables_match mac += { NULL, + "mac", + NETFILTER_VERSION, + IP6T_ALIGN(sizeof(struct ip6t_mac_info)), + IP6T_ALIGN(sizeof(struct ip6t_mac_info)), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match6(&mac); +} diff --git a/extensions/libip6t_multiport.c b/extensions/libip6t_multiport.c new file mode 100644 index 0000000..0fcefde --- /dev/null +++ b/extensions/libip6t_multiport.c @@ -0,0 +1,263 @@ +/* Shared library add-on to iptables to add multiple TCP port support. */ +#include +#include +#include +#include +#include +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"multiport v%s options:\n" +" --source-ports port[,port,port...]\n" +" --sports ...\n" +" match source port(s)\n" +" --destination-ports port[,port,port...]\n" +" --dports ...\n" +" match destination port(s)\n" +" --ports port[,port,port]\n" +" match both source and destination port(s)\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "source-ports", 1, 0, '1' }, + { "sports", 1, 0, '1' }, /* synonym */ + { "destination-ports", 1, 0, '2' }, + { "dports", 1, 0, '2' }, /* synonym */ + { "ports", 1, 0, '3' }, + {0} +}; + +static int +service_to_port(const char *name, const char *proto) +{ + struct servent *service; + + if ((service = getservbyname(name, proto)) != NULL) + return ntohs((unsigned short) service->s_port); + + return -1; +} + +static u_int16_t +parse_port(const char *port, const char *proto) +{ + int portnum; + if ((portnum = string_to_number(port, 0, 65535)) != -1 || + (portnum = service_to_port(port, proto)) != -1) + return (u_int16_t)portnum; + + exit_error(PARAMETER_PROBLEM, + "invalid port/service `%s' specified", port); +} + +static unsigned int +parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) +{ + char *buffer, *cp, *next; + unsigned int i; + + buffer = strdup(portstring); + if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); + + for (cp=buffer, i=0; cp && iipv6.proto == IPPROTO_TCP) + return "tcp"; + else if (entry->ipv6.proto == IPPROTO_UDP) + return "udp"; + else if (!entry->ipv6.proto) + exit_error(PARAMETER_PROBLEM, + "multiport needs `-p tcp' or `-p udp'"); + else + exit_error(PARAMETER_PROBLEM, + "multiport only works with TCP or UDP"); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + const char *proto; + struct ip6t_multiport *multiinfo + = (struct ip6t_multiport *)(*match)->data; + + switch (c) { + case '1': + proto = check_proto(entry); + multiinfo->count = parse_multi_ports(argv[optind-1], + multiinfo->ports, proto); + multiinfo->flags = IP6T_MULTIPORT_SOURCE; + *nfcache |= NFC_IP6_SRC_PT; + break; + + case '2': + proto = check_proto(entry); + multiinfo->count = parse_multi_ports(argv[optind-1], + multiinfo->ports, proto); + multiinfo->flags = IP6T_MULTIPORT_DESTINATION; + *nfcache |= NFC_IP6_DST_PT; + break; + + case '3': + proto = check_proto(entry); + multiinfo->count = parse_multi_ports(argv[optind-1], + multiinfo->ports, proto); + multiinfo->flags = IP6T_MULTIPORT_EITHER; + *nfcache |= NFC_IP6_SRC_PT | NFC_IP6_DST_PT; + break; + + default: + return 0; + } + + if (*flags) + exit_error(PARAMETER_PROBLEM, + "multiport can only have one option"); + *flags = 1; + return 1; +} + +/* Final check; must specify something. */ +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, "multiport expection an option"); +} + +static char * +port_to_service(int port, u_int8_t proto) +{ + struct servent *service; + + if ((service = getservbyport(htons(port), + proto == IPPROTO_TCP ? "tcp" : "udp"))) + return service->s_name; + + return NULL; +} + +static void +print_port(u_int16_t port, u_int8_t protocol, int numeric) +{ + char *service; + + if (numeric || (service = port_to_service(port, protocol)) == NULL) + printf("%u", port); + else + printf("%s", service); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + const struct ip6t_multiport *multiinfo + = (const struct ip6t_multiport *)match->data; + unsigned int i; + + printf("multiport "); + + switch (multiinfo->flags) { + case IP6T_MULTIPORT_SOURCE: + printf("sports "); + break; + + case IP6T_MULTIPORT_DESTINATION: + printf("dports "); + break; + + case IP6T_MULTIPORT_EITHER: + printf("ports "); + break; + + default: + printf("ERROR "); + break; + } + + for (i=0; i < multiinfo->count; i++) { + printf("%s", i ? "," : ""); + print_port(multiinfo->ports[i], ip->proto, numeric); + } + printf(" "); +} + +/* Saves the union ip6t_matchinfo in parsable form to stdout. */ +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + const struct ip6t_multiport *multiinfo + = (const struct ip6t_multiport *)match->data; + unsigned int i; + + switch (multiinfo->flags) { + case IP6T_MULTIPORT_SOURCE: + printf("--sports "); + break; + + case IP6T_MULTIPORT_DESTINATION: + printf("--dports "); + break; + + case IP6T_MULTIPORT_EITHER: + printf("--ports "); + break; + } + + for (i=0; i < multiinfo->count; i++) { + printf("%s", i ? "," : ""); + print_port(multiinfo->ports[i], ip->proto, 0); + } + printf(" "); +} + +struct ip6tables_match multiport += { NULL, + "multiport", + NETFILTER_VERSION, + IP6T_ALIGN(sizeof(struct ip6t_multiport)), + IP6T_ALIGN(sizeof(struct ip6t_multiport)), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void +_init(void) +{ + register_match6(&multiport); +} diff --git a/extensions/libip6t_owner.c b/extensions/libip6t_owner.c new file mode 100644 index 0000000..7648d65 --- /dev/null +++ b/extensions/libip6t_owner.c @@ -0,0 +1,220 @@ +/* Shared library add-on to iptables to add OWNER matching support. */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"OWNER match v%s options:\n" +"[!] --uid-owner userid Match local uid\n" +"[!] --gid-owner groupid Match local gid\n" +"[!] --pid-owner processid Match local pid\n" +"[!] --sid-owner sessionid Match local sid\n" +"\n", +NETFILTER_VERSION); +} + +static struct option opts[] = { + { "uid-owner", 1, 0, '1' }, + { "gid-owner", 1, 0, '2' }, + { "pid-owner", 1, 0, '3' }, + { "sid-owner", 1, 0, '4' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this. */ + *nfcache |= NFC_UNKNOWN; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_owner_info *ownerinfo = (struct ip6t_owner_info *)(*match)->data; + + switch (c) { + char *end; + struct passwd *pwd; + struct group *grp; + case '1': + if (check_inverse(optarg, &invert)) + optind++; + + if ((pwd = getpwnam(optarg))) + ownerinfo->uid = pwd->pw_uid; + else { + ownerinfo->uid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER UID value `%s'", optarg); + } + if (invert) + ownerinfo->invert |= IP6T_OWNER_UID; + ownerinfo->match |= IP6T_OWNER_UID; + *flags = 1; + break; + + case '2': + if (check_inverse(optarg, &invert)) + optind++; + if ((grp = getgrnam(optarg))) + ownerinfo->gid = grp->gr_gid; + else { + ownerinfo->gid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER GID value `%s'", optarg); + } + if (invert) + ownerinfo->invert |= IP6T_OWNER_GID; + ownerinfo->match |= IP6T_OWNER_GID; + *flags = 1; + break; + + case '3': + if (check_inverse(optarg, &invert)) + optind++; + ownerinfo->pid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER PID value `%s'", optarg); + if (invert) + ownerinfo->invert |= IP6T_OWNER_PID; + ownerinfo->match |= IP6T_OWNER_PID; + *flags = 1; + break; + + case '4': + if (check_inverse(optarg, &invert)) + optind++; + ownerinfo->sid = strtoul(optarg, &end, 0); + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad OWNER SID value `%s'", optarg); + if (invert) + ownerinfo->invert |= IP6T_OWNER_SID; + ownerinfo->match |= IP6T_OWNER_SID; + *flags = 1; + break; + + default: + return 0; + } + return 1; +} + +static void +print_item(struct ip6t_owner_info *info, u_int8_t flag, int numeric, char *label) +{ + if(info->match & flag) { + + printf(label); + + if (info->invert & flag) + fputc('!', stdout); + + switch(info->match & flag) { + case IP6T_OWNER_UID: + if(!numeric) { + struct passwd *pwd = getpwuid(info->uid); + + if(pwd && pwd->pw_name) { + printf("%s ", pwd->pw_name); + break; + } + /* FALLTHROUGH */ + } + printf("%u ", info->uid); + break; + case IP6T_OWNER_GID: + if(!numeric) { + struct group *grp = getgrgid(info->gid); + + if(grp && grp->gr_name) { + printf("%s ", grp->gr_name); + break; + } + /* FALLTHROUGH */ + } + printf("%u ", info->gid); + break; + case IP6T_OWNER_PID: + printf("%u ", info->pid); + break; + case IP6T_OWNER_SID: + printf("%u ", info->sid); + break; + default: + break; + } + } +} + +/* Final check; must have specified --own. */ +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "OWNER match: You must specify one or more options"); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + struct ip6t_owner_info *info = (struct ip6t_owner_info *)match->data; + + print_item(info, IP6T_OWNER_UID, numeric, "OWNER UID match "); + print_item(info, IP6T_OWNER_GID, numeric, "OWNER GID match "); + print_item(info, IP6T_OWNER_PID, numeric, "OWNER PID match "); + print_item(info, IP6T_OWNER_SID, numeric, "OWNER SID match "); +} + +/* Saves the union ip6t_matchinfo in parsable form to stdout. */ +static void +save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + struct ip6t_owner_info *info = (struct ip6t_owner_info *)match->data; + + print_item(info, IP6T_OWNER_UID, 0, "--uid-owner "); + print_item(info, IP6T_OWNER_GID, 0, "--gid-owner "); + print_item(info, IP6T_OWNER_PID, 0, "--pid-owner "); + print_item(info, IP6T_OWNER_SID, 0, "--sid-owner "); +} + +struct ip6tables_match owner += { NULL, + "owner", + NETFILTER_VERSION, + IP6T_ALIGN(sizeof(struct ip6t_owner_info)), + IP6T_ALIGN(sizeof(struct ip6t_owner_info)), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match6(&owner); +} -- cgit v1.2.3