From d23b1db6a50de02725a4091ab55c1223c7878db8 Mon Sep 17 00:00:00 2001 From: "/C=JP/ST=JP/CN=Yasuyuki Kozakai/emailAddress=yasuyuki@netfilter.org" Date: Tue, 24 Jul 2007 07:02:26 +0000 Subject: Unifies libip[6]t_sctp.c into libxt_sctp.c --- extensions/.sctp-test6 | 3 - extensions/Makefile | 4 +- extensions/libip6t_sctp.c | 550 ------------------------------- extensions/libipt_sctp.c | 550 ------------------------------- extensions/libxt_sctp.c | 565 ++++++++++++++++++++++++++++++++ include/linux/netfilter/xt_sctp.h | 107 ++++++ include/linux/netfilter_ipv4/ipt_sctp.h | 107 ------ 7 files changed, 674 insertions(+), 1212 deletions(-) delete mode 100755 extensions/.sctp-test6 delete mode 100644 extensions/libip6t_sctp.c delete mode 100644 extensions/libipt_sctp.c create mode 100644 extensions/libxt_sctp.c create mode 100644 include/linux/netfilter/xt_sctp.h delete mode 100644 include/linux/netfilter_ipv4/ipt_sctp.h diff --git a/extensions/.sctp-test6 b/extensions/.sctp-test6 deleted file mode 100755 index 3cfc7b8..0000000 --- a/extensions/.sctp-test6 +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -[ -f $KERNEL_DIR/include/linux/netfilter/xt_sctp.h ] && echo sctp - diff --git a/extensions/Makefile b/extensions/Makefile index 6522b80..2c911b6 100644 --- a/extensions/Makefile +++ b/extensions/Makefile @@ -5,9 +5,9 @@ # header files are present in the include/linux directory of this iptables # package (HW) # -PF_EXT_SLIB:=ah addrtype comment connlimit connmark conntrack dscp ecn esp hashlimit helper icmp iprange length limit mac owner physdev pkttype policy realm sctp state tos ttl unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NFQUEUE REDIRECT REJECT SAME SNAT TCPMSS TOS TTL TRACE ULOG +PF_EXT_SLIB:=ah addrtype comment connlimit connmark conntrack dscp ecn esp hashlimit helper icmp iprange length limit mac owner physdev pkttype policy realm state tos ttl unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NFQUEUE REDIRECT REJECT SAME SNAT TCPMSS TOS TTL TRACE ULOG PF6_EXT_SLIB:=connlimit connmark eui64 hl icmp6 length limit mac owner physdev policy state CONNMARK HL LOG NFQUEUE MARK TCPMSS TRACE -PFX_EXT_SLIB:=mark multiport standard tcp tcpmss udp NOTRACK +PFX_EXT_SLIB:=mark multiport sctp standard tcp tcpmss udp NOTRACK ifeq ($(DO_SELINUX), 1) PF_EXT_SE_SLIB:=SECMARK CONNSECMARK diff --git a/extensions/libip6t_sctp.c b/extensions/libip6t_sctp.c deleted file mode 100644 index d2896e1..0000000 --- a/extensions/libip6t_sctp.c +++ /dev/null @@ -1,550 +0,0 @@ -/* Shared library add-on to iptables for SCTP matching - * - * (C) 2003 by Harald Welte - * - * This program is distributed under the terms of GNU GPL v2, 1991 - * - * libipt_ecn.c borrowed heavily from libipt_dscp.c - * - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -#include - -/* Some ZS!#@:$%*#$! has replaced the ELEMCOUNT macro in ipt_sctp.h with - * ARRAY_SIZE without noticing that this file is used from userserspace, - * and userspace doesn't have ARRAY_SIZE */ - -#ifndef ELEMCOUNT -#define ELEMCOUNT ARRAY_SIZE -#endif - -#if 0 -#define DEBUGP(format, first...) printf(format, ##first) -#define static -#else -#define DEBUGP(format, fist...) -#endif - -static void -print_chunk(u_int32_t chunknum, int numeric); - -/* Initialize the match. */ -static void -init(struct ip6t_entry_match *m, - unsigned int *nfcache) -{ - int i; - struct xt_sctp_info *einfo = (struct xt_sctp_info *)m->data; - - memset(einfo, 0, sizeof(struct xt_sctp_info)); - - for (i = 0; i < XT_NUM_SCTP_FLAGS; i++) { - einfo->flag_info[i].chunktype = -1; - } -} - -static void help(void) -{ - printf( -"SCTP match v%s options\n" -" --source-port [!] port[:port] match source port(s)\n" -" --sport ...\n" -" --destination-port [!] port[:port] match destination port(s)\n" -" --dport ...\n" -" --chunk-types [!] (all|any|none) (chunktype[:flags])+ match if all, any or none of\n" -" chunktypes are present\n" -"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK ALL NONE\n", - IPTABLES_VERSION); -} - -static struct option opts[] = { - { .name = "source-port", .has_arg = 1, .flag = 0, .val = '1' }, - { .name = "sport", .has_arg = 1, .flag = 0, .val = '1' }, - { .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' }, - { .name = "dport", .has_arg = 1, .flag = 0, .val = '2' }, - { .name = "chunk-types", .has_arg = 1, .flag = 0, .val = '3' }, - { .name = 0 } -}; - -static void -parse_sctp_ports(const char *portstring, - u_int16_t *ports) -{ - char *buffer; - char *cp; - - buffer = strdup(portstring); - DEBUGP("%s\n", portstring); - if ((cp = strchr(buffer, ':')) == NULL) { - ports[0] = ports[1] = parse_port(buffer, "sctp"); - } - else { - *cp = '\0'; - cp++; - - ports[0] = buffer[0] ? parse_port(buffer, "sctp") : 0; - ports[1] = cp[0] ? parse_port(cp, "sctp") : 0xFFFF; - - if (ports[0] > ports[1]) - exit_error(PARAMETER_PROBLEM, - "invalid portrange (min > max)"); - } - free(buffer); -} - -struct sctp_chunk_names { - const char *name; - unsigned int chunk_type; - const char *valid_flags; -}; - -/*'ALL' and 'NONE' will be treated specially. */ -static struct sctp_chunk_names sctp_chunk_names[] -= { { .name = "DATA", .chunk_type = 0, .valid_flags = "-----UBE"}, - { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"}, - { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"}, - { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"}, - { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"}, - { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"}, - { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"}, - { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"}, - { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"}, - { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"}, - { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"}, - { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"}, - { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"}, - { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"}, - { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"}, - { .name = "ASCONF", .chunk_type = 31, .valid_flags = "--------"}, - { .name = "ASCONF_ACK", .chunk_type = 30, .valid_flags = "--------"}, -}; - -static void -save_chunk_flag_info(struct xt_sctp_flag_info *flag_info, - int *flag_count, - int chunktype, - int bit, - int set) -{ - int i; - - for (i = 0; i < *flag_count; i++) { - if (flag_info[i].chunktype == chunktype) { - DEBUGP("Previous match found\n"); - flag_info[i].chunktype = chunktype; - flag_info[i].flag_mask |= (1 << bit); - if (set) { - flag_info[i].flag |= (1 << bit); - } - - return; - } - } - - if (*flag_count == XT_NUM_SCTP_FLAGS) { - exit_error (PARAMETER_PROBLEM, - "Number of chunk types with flags exceeds currently allowed limit." - "Increasing this limit involves changing XT_NUM_SCTP_FLAGS and" - "recompiling both the kernel space and user space modules\n"); - } - - flag_info[*flag_count].chunktype = chunktype; - flag_info[*flag_count].flag_mask |= (1 << bit); - if (set) { - flag_info[*flag_count].flag |= (1 << bit); - } - (*flag_count)++; -} - -static void -parse_sctp_chunk(struct xt_sctp_info *einfo, - const char *chunks) -{ - char *ptr; - char *buffer; - unsigned int i, j; - int found = 0; - char *chunk_flags; - - buffer = strdup(chunks); - DEBUGP("Buffer: %s\n", buffer); - - SCTP_CHUNKMAP_RESET(einfo->chunkmap); - - if (!strcasecmp(buffer, "ALL")) { - SCTP_CHUNKMAP_SET_ALL(einfo->chunkmap); - goto out; - } - - if (!strcasecmp(buffer, "NONE")) { - SCTP_CHUNKMAP_RESET(einfo->chunkmap); - goto out; - } - - for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { - found = 0; - DEBUGP("Next Chunk type %s\n", ptr); - - if ((chunk_flags = strchr(ptr, ':')) != NULL) { - *chunk_flags++ = 0; - } - - for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) { - if (strcasecmp(sctp_chunk_names[i].name, ptr) == 0) { - DEBUGP("Chunk num %d\n", sctp_chunk_names[i].chunk_type); - SCTP_CHUNKMAP_SET(einfo->chunkmap, - sctp_chunk_names[i].chunk_type); - found = 1; - break; - } - } - if (!found) - exit_error(PARAMETER_PROBLEM, - "Unknown sctp chunk `%s'", ptr); - - if (chunk_flags) { - DEBUGP("Chunk flags %s\n", chunk_flags); - for (j = 0; j < strlen(chunk_flags); j++) { - char *p; - int bit; - - if ((p = strchr(sctp_chunk_names[i].valid_flags, - toupper(chunk_flags[j]))) != NULL) { - bit = p - sctp_chunk_names[i].valid_flags; - bit = 7 - bit; - - save_chunk_flag_info(einfo->flag_info, - &(einfo->flag_count), i, bit, - isupper(chunk_flags[j])); - } else { - exit_error(PARAMETER_PROBLEM, - "Invalid flags for chunk type %d\n", i); - } - } - } - } -out: - free(buffer); -} - -static void -parse_sctp_chunks(struct xt_sctp_info *einfo, - const char *match_type, - const char *chunks) -{ - DEBUGP("Match type: %s Chunks: %s\n", match_type, chunks); - if (!strcasecmp(match_type, "ANY")) { - einfo->chunk_match_type = SCTP_CHUNK_MATCH_ANY; - } else if (!strcasecmp(match_type, "ALL")) { - einfo->chunk_match_type = SCTP_CHUNK_MATCH_ALL; - } else if (!strcasecmp(match_type, "ONLY")) { - einfo->chunk_match_type = SCTP_CHUNK_MATCH_ONLY; - } else { - exit_error (PARAMETER_PROBLEM, - "Match type has to be one of \"ALL\", \"ANY\" or \"ONLY\""); - } - - SCTP_CHUNKMAP_RESET(einfo->chunkmap); - parse_sctp_chunk(einfo, chunks); -} - -static int -parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, - unsigned int *nfcache, - struct ip6t_entry_match **match) -{ - struct xt_sctp_info *einfo - = (struct xt_sctp_info *)(*match)->data; - - switch (c) { - case '1': - if (*flags & XT_SCTP_SRC_PORTS) - exit_error(PARAMETER_PROBLEM, - "Only one `--source-port' allowed"); - einfo->flags |= XT_SCTP_SRC_PORTS; - check_inverse(optarg, &invert, &optind, 0); - parse_sctp_ports(argv[optind-1], einfo->spts); - if (invert) - einfo->invflags |= XT_SCTP_SRC_PORTS; - *flags |= XT_SCTP_SRC_PORTS; - break; - - case '2': - if (*flags & XT_SCTP_DEST_PORTS) - exit_error(PARAMETER_PROBLEM, - "Only one `--destination-port' allowed"); - einfo->flags |= XT_SCTP_DEST_PORTS; - check_inverse(optarg, &invert, &optind, 0); - parse_sctp_ports(argv[optind-1], einfo->dpts); - if (invert) - einfo->invflags |= XT_SCTP_DEST_PORTS; - *flags |= XT_SCTP_DEST_PORTS; - break; - - case '3': - if (*flags & XT_SCTP_CHUNK_TYPES) - exit_error(PARAMETER_PROBLEM, - "Only one `--chunk-types' allowed"); - check_inverse(optarg, &invert, &optind, 0); - - if (!argv[optind] - || argv[optind][0] == '-' || argv[optind][0] == '!') - exit_error(PARAMETER_PROBLEM, - "--chunk-types requires two args"); - - einfo->flags |= XT_SCTP_CHUNK_TYPES; - parse_sctp_chunks(einfo, argv[optind-1], argv[optind]); - if (invert) - einfo->invflags |= XT_SCTP_CHUNK_TYPES; - optind++; - *flags |= XT_SCTP_CHUNK_TYPES; - break; - - default: - return 0; - } - return 1; -} - -static void -final_check(unsigned int flags) -{ -} - -static char * -port_to_service(int port) -{ - struct servent *service; - - if ((service = getservbyport(htons(port), "sctp"))) - return service->s_name; - - return NULL; -} - -static void -print_port(u_int16_t port, int numeric) -{ - char *service; - - if (numeric || (service = port_to_service(port)) == NULL) - printf("%u", port); - else - printf("%s", service); -} - -static void -print_ports(const char *name, u_int16_t min, u_int16_t max, - int invert, int numeric) -{ - const char *inv = invert ? "!" : ""; - - if (min != 0 || max != 0xFFFF || invert) { - printf("%s", name); - if (min == max) { - printf(":%s", inv); - print_port(min, numeric); - } else { - printf("s:%s", inv); - print_port(min, numeric); - printf(":"); - print_port(max, numeric); - } - printf(" "); - } -} - -static void -print_chunk_flags(u_int32_t chunknum, u_int8_t chunk_flags, u_int8_t chunk_flags_mask) -{ - int i; - - DEBUGP("type: %d\tflags: %x\tflag mask: %x\n", chunknum, chunk_flags, - chunk_flags_mask); - - if (chunk_flags_mask) { - printf(":"); - } - - for (i = 7; i >= 0; i--) { - if (chunk_flags_mask & (1 << i)) { - if (chunk_flags & (1 << i)) { - printf("%c", sctp_chunk_names[chunknum].valid_flags[7-i]); - } else { - printf("%c", tolower(sctp_chunk_names[chunknum].valid_flags[7-i])); - } - } - } -} - -static void -print_chunk(u_int32_t chunknum, int numeric) -{ - if (numeric) { - printf("0x%04X", chunknum); - } - else { - int i; - - for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) { - if (sctp_chunk_names[i].chunk_type == chunknum) - printf("%s", sctp_chunk_names[chunknum].name); - } - } -} - -static void -print_chunks(u_int32_t chunk_match_type, - const u_int32_t *chunkmap, - const struct xt_sctp_flag_info *flag_info, - int flag_count, - int numeric) -{ - int i, j; - int flag; - - switch (chunk_match_type) { - case SCTP_CHUNK_MATCH_ANY: printf("any "); break; - case SCTP_CHUNK_MATCH_ALL: printf("all "); break; - case SCTP_CHUNK_MATCH_ONLY: printf("only "); break; - default: printf("Never reach herer\n"); break; - } - - if (SCTP_CHUNKMAP_IS_CLEAR(chunkmap)) { - printf("NONE "); - goto out; - } - - if (SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)) { - printf("ALL "); - goto out; - } - - flag = 0; - for (i = 0; i < 256; i++) { - if (SCTP_CHUNKMAP_IS_SET(chunkmap, i)) { - if (flag) - printf(","); - flag = 1; - print_chunk(i, numeric); - for (j = 0; j < flag_count; j++) { - if (flag_info[j].chunktype == i) { - print_chunk_flags(i, flag_info[j].flag, - flag_info[j].flag_mask); - } - } - } - } - - if (flag) - printf(" "); -out: - return; -} - -/* Prints out the matchinfo. */ -static void -print(const void *ip, - const struct ip6t_entry_match *match, - int numeric) -{ - const struct xt_sctp_info *einfo = - (const struct xt_sctp_info *)match->data; - - printf("sctp "); - - if (einfo->flags & XT_SCTP_SRC_PORTS) { - print_ports("spt", einfo->spts[0], einfo->spts[1], - einfo->invflags & XT_SCTP_SRC_PORTS, - numeric); - } - - if (einfo->flags & XT_SCTP_DEST_PORTS) { - print_ports("dpt", einfo->dpts[0], einfo->dpts[1], - einfo->invflags & XT_SCTP_DEST_PORTS, - numeric); - } - - if (einfo->flags & XT_SCTP_CHUNK_TYPES) { - /* FIXME: print_chunks() is used in save() where the printing of '!' - s taken care of, so we need to do that here as well */ - if (einfo->invflags & XT_SCTP_CHUNK_TYPES) { - printf("! "); - } - print_chunks(einfo->chunk_match_type, einfo->chunkmap, - einfo->flag_info, einfo->flag_count, numeric); - } -} - -/* Saves the union xt_matchinfo in parsable form to stdout. */ -static void -save(const void *ip, - const struct ip6t_entry_match *match) -{ - const struct xt_sctp_info *einfo = - (const struct xt_sctp_info *)match->data; - - if (einfo->flags & XT_SCTP_SRC_PORTS) { - if (einfo->invflags & XT_SCTP_SRC_PORTS) - printf("! "); - if (einfo->spts[0] != einfo->spts[1]) - printf("--sport %u:%u ", - einfo->spts[0], einfo->spts[1]); - else - printf("--sport %u ", einfo->spts[0]); - } - - if (einfo->flags & XT_SCTP_DEST_PORTS) { - if (einfo->invflags & XT_SCTP_DEST_PORTS) - printf("! "); - if (einfo->dpts[0] != einfo->dpts[1]) - printf("--dport %u:%u ", - einfo->dpts[0], einfo->dpts[1]); - else - printf("--dport %u ", einfo->dpts[0]); - } - - if (einfo->flags & XT_SCTP_CHUNK_TYPES) { - if (einfo->invflags & XT_SCTP_CHUNK_TYPES) - printf("! "); - printf("--chunk-types "); - - print_chunks(einfo->chunk_match_type, einfo->chunkmap, - einfo->flag_info, einfo->flag_count, 0); - } -} - -static -struct ip6tables_match sctp -= { .name = "sctp", - .version = IPTABLES_VERSION, - .size = IP6T_ALIGN(sizeof(struct xt_sctp_info)), - .userspacesize = IP6T_ALIGN(sizeof(struct xt_sctp_info)), - .help = &help, - .init = &init, - .parse = &parse, - .final_check = &final_check, - .print = &print, - .save = &save, - .extra_opts = opts -}; - -void _init(void) -{ - register_match6(&sctp); -} - diff --git a/extensions/libipt_sctp.c b/extensions/libipt_sctp.c deleted file mode 100644 index 89b65fc..0000000 --- a/extensions/libipt_sctp.c +++ /dev/null @@ -1,550 +0,0 @@ -/* Shared library add-on to iptables for SCTP matching - * - * (C) 2003 by Harald Welte - * - * This program is distributed under the terms of GNU GPL v2, 1991 - * - * libipt_ecn.c borrowed heavily from libipt_dscp.c - * - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -#include - -/* Some ZS!#@:$%*#$! has replaced the ELEMCOUNT macro in ipt_sctp.h with - * ARRAY_SIZE without noticing that this file is used from userserspace, - * and userspace doesn't have ARRAY_SIZE */ - -#ifndef ELEMCOUNT -#define ELEMCOUNT ARRAY_SIZE -#endif - -#if 0 -#define DEBUGP(format, first...) printf(format, ##first) -#define static -#else -#define DEBUGP(format, fist...) -#endif - -static void -print_chunk(u_int32_t chunknum, int numeric); - -/* Initialize the match. */ -static void -init(struct xt_entry_match *m, - unsigned int *nfcache) -{ - int i; - struct ipt_sctp_info *einfo = (struct ipt_sctp_info *)m->data; - - memset(einfo, 0, sizeof(struct ipt_sctp_info)); - - for (i = 0; i < IPT_NUM_SCTP_FLAGS; i++) { - einfo->flag_info[i].chunktype = -1; - } -} - -static void help(void) -{ - printf( -"SCTP match v%s options\n" -" --source-port [!] port[:port] match source port(s)\n" -" --sport ...\n" -" --destination-port [!] port[:port] match destination port(s)\n" -" --dport ...\n" -" --chunk-types [!] (all|any|none) (chunktype[:flags])+ match if all, any or none of\n" -" chunktypes are present\n" -"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK ALL NONE\n", - IPTABLES_VERSION); -} - -static struct option opts[] = { - { .name = "source-port", .has_arg = 1, .flag = 0, .val = '1' }, - { .name = "sport", .has_arg = 1, .flag = 0, .val = '1' }, - { .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' }, - { .name = "dport", .has_arg = 1, .flag = 0, .val = '2' }, - { .name = "chunk-types", .has_arg = 1, .flag = 0, .val = '3' }, - { .name = 0 } -}; - -static void -parse_sctp_ports(const char *portstring, - u_int16_t *ports) -{ - char *buffer; - char *cp; - - buffer = strdup(portstring); - DEBUGP("%s\n", portstring); - if ((cp = strchr(buffer, ':')) == NULL) { - ports[0] = ports[1] = parse_port(buffer, "sctp"); - } - else { - *cp = '\0'; - cp++; - - ports[0] = buffer[0] ? parse_port(buffer, "sctp") : 0; - ports[1] = cp[0] ? parse_port(cp, "sctp") : 0xFFFF; - - if (ports[0] > ports[1]) - exit_error(PARAMETER_PROBLEM, - "invalid portrange (min > max)"); - } - free(buffer); -} - -struct sctp_chunk_names { - const char *name; - unsigned int chunk_type; - const char *valid_flags; -}; - -/*'ALL' and 'NONE' will be treated specially. */ -static struct sctp_chunk_names sctp_chunk_names[] -= { { .name = "DATA", .chunk_type = 0, .valid_flags = "-----UBE"}, - { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"}, - { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"}, - { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"}, - { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"}, - { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"}, - { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"}, - { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"}, - { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"}, - { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"}, - { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"}, - { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"}, - { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"}, - { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"}, - { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"}, - { .name = "ASCONF", .chunk_type = 31, .valid_flags = "--------"}, - { .name = "ASCONF_ACK", .chunk_type = 30, .valid_flags = "--------"}, -}; - -static void -save_chunk_flag_info(struct ipt_sctp_flag_info *flag_info, - int *flag_count, - int chunktype, - int bit, - int set) -{ - int i; - - for (i = 0; i < *flag_count; i++) { - if (flag_info[i].chunktype == chunktype) { - DEBUGP("Previous match found\n"); - flag_info[i].chunktype = chunktype; - flag_info[i].flag_mask |= (1 << bit); - if (set) { - flag_info[i].flag |= (1 << bit); - } - - return; - } - } - - if (*flag_count == IPT_NUM_SCTP_FLAGS) { - exit_error (PARAMETER_PROBLEM, - "Number of chunk types with flags exceeds currently allowed limit." - "Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and" - "recompiling both the kernel space and user space modules\n"); - } - - flag_info[*flag_count].chunktype = chunktype; - flag_info[*flag_count].flag_mask |= (1 << bit); - if (set) { - flag_info[*flag_count].flag |= (1 << bit); - } - (*flag_count)++; -} - -static void -parse_sctp_chunk(struct ipt_sctp_info *einfo, - const char *chunks) -{ - char *ptr; - char *buffer; - unsigned int i, j; - int found = 0; - char *chunk_flags; - - buffer = strdup(chunks); - DEBUGP("Buffer: %s\n", buffer); - - SCTP_CHUNKMAP_RESET(einfo->chunkmap); - - if (!strcasecmp(buffer, "ALL")) { - SCTP_CHUNKMAP_SET_ALL(einfo->chunkmap); - goto out; - } - - if (!strcasecmp(buffer, "NONE")) { - SCTP_CHUNKMAP_RESET(einfo->chunkmap); - goto out; - } - - for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { - found = 0; - DEBUGP("Next Chunk type %s\n", ptr); - - if ((chunk_flags = strchr(ptr, ':')) != NULL) { - *chunk_flags++ = 0; - } - - for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) { - if (strcasecmp(sctp_chunk_names[i].name, ptr) == 0) { - DEBUGP("Chunk num %d\n", sctp_chunk_names[i].chunk_type); - SCTP_CHUNKMAP_SET(einfo->chunkmap, - sctp_chunk_names[i].chunk_type); - found = 1; - break; - } - } - if (!found) - exit_error(PARAMETER_PROBLEM, - "Unknown sctp chunk `%s'", ptr); - - if (chunk_flags) { - DEBUGP("Chunk flags %s\n", chunk_flags); - for (j = 0; j < strlen(chunk_flags); j++) { - char *p; - int bit; - - if ((p = strchr(sctp_chunk_names[i].valid_flags, - toupper(chunk_flags[j]))) != NULL) { - bit = p - sctp_chunk_names[i].valid_flags; - bit = 7 - bit; - - save_chunk_flag_info(einfo->flag_info, - &(einfo->flag_count), i, bit, - isupper(chunk_flags[j])); - } else { - exit_error(PARAMETER_PROBLEM, - "Invalid flags for chunk type %d\n", i); - } - } - } - } -out: - free(buffer); -} - -static void -parse_sctp_chunks(struct ipt_sctp_info *einfo, - const char *match_type, - const char *chunks) -{ - DEBUGP("Match type: %s Chunks: %s\n", match_type, chunks); - if (!strcasecmp(match_type, "ANY")) { - einfo->chunk_match_type = SCTP_CHUNK_MATCH_ANY; - } else if (!strcasecmp(match_type, "ALL")) { - einfo->chunk_match_type = SCTP_CHUNK_MATCH_ALL; - } else if (!strcasecmp(match_type, "ONLY")) { - einfo->chunk_match_type = SCTP_CHUNK_MATCH_ONLY; - } else { - exit_error (PARAMETER_PROBLEM, - "Match type has to be one of \"ALL\", \"ANY\" or \"ONLY\""); - } - - SCTP_CHUNKMAP_RESET(einfo->chunkmap); - parse_sctp_chunk(einfo, chunks); -} - -static int -parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, - unsigned int *nfcache, - struct xt_entry_match **match) -{ - struct ipt_sctp_info *einfo - = (struct ipt_sctp_info *)(*match)->data; - - switch (c) { - case '1': - if (*flags & IPT_SCTP_SRC_PORTS) - exit_error(PARAMETER_PROBLEM, - "Only one `--source-port' allowed"); - einfo->flags |= IPT_SCTP_SRC_PORTS; - check_inverse(optarg, &invert, &optind, 0); - parse_sctp_ports(argv[optind-1], einfo->spts); - if (invert) - einfo->invflags |= IPT_SCTP_SRC_PORTS; - *flags |= IPT_SCTP_SRC_PORTS; - break; - - case '2': - if (*flags & IPT_SCTP_DEST_PORTS) - exit_error(PARAMETER_PROBLEM, - "Only one `--destination-port' allowed"); - einfo->flags |= IPT_SCTP_DEST_PORTS; - check_inverse(optarg, &invert, &optind, 0); - parse_sctp_ports(argv[optind-1], einfo->dpts); - if (invert) - einfo->invflags |= IPT_SCTP_DEST_PORTS; - *flags |= IPT_SCTP_DEST_PORTS; - break; - - case '3': - if (*flags & IPT_SCTP_CHUNK_TYPES) - exit_error(PARAMETER_PROBLEM, - "Only one `--chunk-types' allowed"); - check_inverse(optarg, &invert, &optind, 0); - - if (!argv[optind] - || argv[optind][0] == '-' || argv[optind][0] == '!') - exit_error(PARAMETER_PROBLEM, - "--chunk-types requires two args"); - - einfo->flags |= IPT_SCTP_CHUNK_TYPES; - parse_sctp_chunks(einfo, argv[optind-1], argv[optind]); - if (invert) - einfo->invflags |= IPT_SCTP_CHUNK_TYPES; - optind++; - *flags |= IPT_SCTP_CHUNK_TYPES; - break; - - default: - return 0; - } - return 1; -} - -static void -final_check(unsigned int flags) -{ -} - -static char * -port_to_service(int port) -{ - struct servent *service; - - if ((service = getservbyport(htons(port), "sctp"))) - return service->s_name; - - return NULL; -} - -static void -print_port(u_int16_t port, int numeric) -{ - char *service; - - if (numeric || (service = port_to_service(port)) == NULL) - printf("%u", port); - else - printf("%s", service); -} - -static void -print_ports(const char *name, u_int16_t min, u_int16_t max, - int invert, int numeric) -{ - const char *inv = invert ? "!" : ""; - - if (min != 0 || max != 0xFFFF || invert) { - printf("%s", name); - if (min == max) { - printf(":%s", inv); - print_port(min, numeric); - } else { - printf("s:%s", inv); - print_port(min, numeric); - printf(":"); - print_port(max, numeric); - } - printf(" "); - } -} - -static void -print_chunk_flags(u_int32_t chunknum, u_int8_t chunk_flags, u_int8_t chunk_flags_mask) -{ - int i; - - DEBUGP("type: %d\tflags: %x\tflag mask: %x\n", chunknum, chunk_flags, - chunk_flags_mask); - - if (chunk_flags_mask) { - printf(":"); - } - - for (i = 7; i >= 0; i--) { - if (chunk_flags_mask & (1 << i)) { - if (chunk_flags & (1 << i)) { - printf("%c", sctp_chunk_names[chunknum].valid_flags[7-i]); - } else { - printf("%c", tolower(sctp_chunk_names[chunknum].valid_flags[7-i])); - } - } - } -} - -static void -print_chunk(u_int32_t chunknum, int numeric) -{ - if (numeric) { - printf("0x%04X", chunknum); - } - else { - int i; - - for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) { - if (sctp_chunk_names[i].chunk_type == chunknum) - printf("%s", sctp_chunk_names[chunknum].name); - } - } -} - -static void -print_chunks(u_int32_t chunk_match_type, - const u_int32_t *chunkmap, - const struct ipt_sctp_flag_info *flag_info, - int flag_count, - int numeric) -{ - int i, j; - int flag; - - switch (chunk_match_type) { - case SCTP_CHUNK_MATCH_ANY: printf("any "); break; - case SCTP_CHUNK_MATCH_ALL: printf("all "); break; - case SCTP_CHUNK_MATCH_ONLY: printf("only "); break; - default: printf("Never reach herer\n"); break; - } - - if (SCTP_CHUNKMAP_IS_CLEAR(chunkmap)) { - printf("NONE "); - goto out; - } - - if (SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)) { - printf("ALL "); - goto out; - } - - flag = 0; - for (i = 0; i < 256; i++) { - if (SCTP_CHUNKMAP_IS_SET(chunkmap, i)) { - if (flag) - printf(","); - flag = 1; - print_chunk(i, numeric); - for (j = 0; j < flag_count; j++) { - if (flag_info[j].chunktype == i) { - print_chunk_flags(i, flag_info[j].flag, - flag_info[j].flag_mask); - } - } - } - } - - if (flag) - printf(" "); -out: - return; -} - -/* Prints out the matchinfo. */ -static void -print(const void *ip, - const struct xt_entry_match *match, - int numeric) -{ - const struct ipt_sctp_info *einfo = - (const struct ipt_sctp_info *)match->data; - - printf("sctp "); - - if (einfo->flags & IPT_SCTP_SRC_PORTS) { - print_ports("spt", einfo->spts[0], einfo->spts[1], - einfo->invflags & IPT_SCTP_SRC_PORTS, - numeric); - } - - if (einfo->flags & IPT_SCTP_DEST_PORTS) { - print_ports("dpt", einfo->dpts[0], einfo->dpts[1], - einfo->invflags & IPT_SCTP_DEST_PORTS, - numeric); - } - - if (einfo->flags & IPT_SCTP_CHUNK_TYPES) { - /* FIXME: print_chunks() is used in save() where the printing of '!' - s taken care of, so we need to do that here as well */ - if (einfo->invflags & IPT_SCTP_CHUNK_TYPES) { - printf("! "); - } - print_chunks(einfo->chunk_match_type, einfo->chunkmap, - einfo->flag_info, einfo->flag_count, numeric); - } -} - -/* Saves the union ipt_matchinfo in parsable form to stdout. */ -static void -save(const void *ip, - const struct xt_entry_match *match) -{ - const struct ipt_sctp_info *einfo = - (const struct ipt_sctp_info *)match->data; - - if (einfo->flags & IPT_SCTP_SRC_PORTS) { - if (einfo->invflags & IPT_SCTP_SRC_PORTS) - printf("! "); - if (einfo->spts[0] != einfo->spts[1]) - printf("--sport %u:%u ", - einfo->spts[0], einfo->spts[1]); - else - printf("--sport %u ", einfo->spts[0]); - } - - if (einfo->flags & IPT_SCTP_DEST_PORTS) { - if (einfo->invflags & IPT_SCTP_DEST_PORTS) - printf("! "); - if (einfo->dpts[0] != einfo->dpts[1]) - printf("--dport %u:%u ", - einfo->dpts[0], einfo->dpts[1]); - else - printf("--dport %u ", einfo->dpts[0]); - } - - if (einfo->flags & IPT_SCTP_CHUNK_TYPES) { - if (einfo->invflags & IPT_SCTP_CHUNK_TYPES) - printf("! "); - printf("--chunk-types "); - - print_chunks(einfo->chunk_match_type, einfo->chunkmap, - einfo->flag_info, einfo->flag_count, 0); - } -} - -static -struct iptables_match sctp -= { .name = "sctp", - .version = IPTABLES_VERSION, - .size = IPT_ALIGN(sizeof(struct ipt_sctp_info)), - .userspacesize = IPT_ALIGN(sizeof(struct ipt_sctp_info)), - .help = &help, - .init = &init, - .parse = &parse, - .final_check = &final_check, - .print = &print, - .save = &save, - .extra_opts = opts -}; - -void _init(void) -{ - register_match(&sctp); -} - diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c new file mode 100644 index 0000000..5d23f09 --- /dev/null +++ b/extensions/libxt_sctp.c @@ -0,0 +1,565 @@ +/* Shared library add-on to iptables for SCTP matching + * + * (C) 2003 by Harald Welte + * + * This program is distributed under the terms of GNU GPL v2, 1991 + * + * libipt_ecn.c borrowed heavily from libipt_dscp.c + * + */ +#include +#include +#include +#include +#include +#include + +#include + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#include + +/* Some ZS!#@:$%*#$! has replaced the ELEMCOUNT macro in ipt_sctp.h with + * ARRAY_SIZE without noticing that this file is used from userserspace, + * and userspace doesn't have ARRAY_SIZE */ + +#ifndef ELEMCOUNT +#define ELEMCOUNT ARRAY_SIZE +#endif + +#if 0 +#define DEBUGP(format, first...) printf(format, ##first) +#define static +#else +#define DEBUGP(format, fist...) +#endif + +static void +print_chunk(u_int32_t chunknum, int numeric); + +/* Initialize the match. */ +static void +init(struct xt_entry_match *m, + unsigned int *nfcache) +{ + int i; + struct xt_sctp_info *einfo = (struct xt_sctp_info *)m->data; + + memset(einfo, 0, sizeof(struct xt_sctp_info)); + + for (i = 0; i < XT_NUM_SCTP_FLAGS; i++) { + einfo->flag_info[i].chunktype = -1; + } +} + +static void help(void) +{ + printf( +"SCTP match v%s options\n" +" --source-port [!] port[:port] match source port(s)\n" +" --sport ...\n" +" --destination-port [!] port[:port] match destination port(s)\n" +" --dport ...\n" +" --chunk-types [!] (all|any|none) (chunktype[:flags])+ match if all, any or none of\n" +" chunktypes are present\n" +"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK ALL NONE\n", + IPTABLES_VERSION); +} + +static struct option opts[] = { + { .name = "source-port", .has_arg = 1, .flag = 0, .val = '1' }, + { .name = "sport", .has_arg = 1, .flag = 0, .val = '1' }, + { .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' }, + { .name = "dport", .has_arg = 1, .flag = 0, .val = '2' }, + { .name = "chunk-types", .has_arg = 1, .flag = 0, .val = '3' }, + { .name = 0 } +}; + +static void +parse_sctp_ports(const char *portstring, + u_int16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + DEBUGP("%s\n", portstring); + if ((cp = strchr(buffer, ':')) == NULL) { + ports[0] = ports[1] = parse_port(buffer, "sctp"); + } + else { + *cp = '\0'; + cp++; + + ports[0] = buffer[0] ? parse_port(buffer, "sctp") : 0; + ports[1] = cp[0] ? parse_port(cp, "sctp") : 0xFFFF; + + if (ports[0] > ports[1]) + exit_error(PARAMETER_PROBLEM, + "invalid portrange (min > max)"); + } + free(buffer); +} + +struct sctp_chunk_names { + const char *name; + unsigned int chunk_type; + const char *valid_flags; +}; + +/*'ALL' and 'NONE' will be treated specially. */ +static struct sctp_chunk_names sctp_chunk_names[] += { { .name = "DATA", .chunk_type = 0, .valid_flags = "-----UBE"}, + { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"}, + { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"}, + { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"}, + { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"}, + { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"}, + { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"}, + { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"}, + { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"}, + { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"}, + { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"}, + { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"}, + { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"}, + { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"}, + { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"}, + { .name = "ASCONF", .chunk_type = 31, .valid_flags = "--------"}, + { .name = "ASCONF_ACK", .chunk_type = 30, .valid_flags = "--------"}, +}; + +static void +save_chunk_flag_info(struct xt_sctp_flag_info *flag_info, + int *flag_count, + int chunktype, + int bit, + int set) +{ + int i; + + for (i = 0; i < *flag_count; i++) { + if (flag_info[i].chunktype == chunktype) { + DEBUGP("Previous match found\n"); + flag_info[i].chunktype = chunktype; + flag_info[i].flag_mask |= (1 << bit); + if (set) { + flag_info[i].flag |= (1 << bit); + } + + return; + } + } + + if (*flag_count == XT_NUM_SCTP_FLAGS) { + exit_error (PARAMETER_PROBLEM, + "Number of chunk types with flags exceeds currently allowed limit." + "Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and" + "recompiling both the kernel space and user space modules\n"); + } + + flag_info[*flag_count].chunktype = chunktype; + flag_info[*flag_count].flag_mask |= (1 << bit); + if (set) { + flag_info[*flag_count].flag |= (1 << bit); + } + (*flag_count)++; +} + +static void +parse_sctp_chunk(struct xt_sctp_info *einfo, + const char *chunks) +{ + char *ptr; + char *buffer; + unsigned int i, j; + int found = 0; + char *chunk_flags; + + buffer = strdup(chunks); + DEBUGP("Buffer: %s\n", buffer); + + SCTP_CHUNKMAP_RESET(einfo->chunkmap); + + if (!strcasecmp(buffer, "ALL")) { + SCTP_CHUNKMAP_SET_ALL(einfo->chunkmap); + goto out; + } + + if (!strcasecmp(buffer, "NONE")) { + SCTP_CHUNKMAP_RESET(einfo->chunkmap); + goto out; + } + + for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { + found = 0; + DEBUGP("Next Chunk type %s\n", ptr); + + if ((chunk_flags = strchr(ptr, ':')) != NULL) { + *chunk_flags++ = 0; + } + + for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) { + if (strcasecmp(sctp_chunk_names[i].name, ptr) == 0) { + DEBUGP("Chunk num %d\n", sctp_chunk_names[i].chunk_type); + SCTP_CHUNKMAP_SET(einfo->chunkmap, + sctp_chunk_names[i].chunk_type); + found = 1; + break; + } + } + if (!found) + exit_error(PARAMETER_PROBLEM, + "Unknown sctp chunk `%s'", ptr); + + if (chunk_flags) { + DEBUGP("Chunk flags %s\n", chunk_flags); + for (j = 0; j < strlen(chunk_flags); j++) { + char *p; + int bit; + + if ((p = strchr(sctp_chunk_names[i].valid_flags, + toupper(chunk_flags[j]))) != NULL) { + bit = p - sctp_chunk_names[i].valid_flags; + bit = 7 - bit; + + save_chunk_flag_info(einfo->flag_info, + &(einfo->flag_count), i, bit, + isupper(chunk_flags[j])); + } else { + exit_error(PARAMETER_PROBLEM, + "Invalid flags for chunk type %d\n", i); + } + } + } + } +out: + free(buffer); +} + +static void +parse_sctp_chunks(struct xt_sctp_info *einfo, + const char *match_type, + const char *chunks) +{ + DEBUGP("Match type: %s Chunks: %s\n", match_type, chunks); + if (!strcasecmp(match_type, "ANY")) { + einfo->chunk_match_type = SCTP_CHUNK_MATCH_ANY; + } else if (!strcasecmp(match_type, "ALL")) { + einfo->chunk_match_type = SCTP_CHUNK_MATCH_ALL; + } else if (!strcasecmp(match_type, "ONLY")) { + einfo->chunk_match_type = SCTP_CHUNK_MATCH_ONLY; + } else { + exit_error (PARAMETER_PROBLEM, + "Match type has to be one of \"ALL\", \"ANY\" or \"ONLY\""); + } + + SCTP_CHUNKMAP_RESET(einfo->chunkmap); + parse_sctp_chunk(einfo, chunks); +} + +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, + unsigned int *nfcache, + struct xt_entry_match **match) +{ + struct xt_sctp_info *einfo + = (struct xt_sctp_info *)(*match)->data; + + switch (c) { + case '1': + if (*flags & XT_SCTP_SRC_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--source-port' allowed"); + einfo->flags |= XT_SCTP_SRC_PORTS; + check_inverse(optarg, &invert, &optind, 0); + parse_sctp_ports(argv[optind-1], einfo->spts); + if (invert) + einfo->invflags |= XT_SCTP_SRC_PORTS; + *flags |= XT_SCTP_SRC_PORTS; + break; + + case '2': + if (*flags & XT_SCTP_DEST_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--destination-port' allowed"); + einfo->flags |= XT_SCTP_DEST_PORTS; + check_inverse(optarg, &invert, &optind, 0); + parse_sctp_ports(argv[optind-1], einfo->dpts); + if (invert) + einfo->invflags |= XT_SCTP_DEST_PORTS; + *flags |= XT_SCTP_DEST_PORTS; + break; + + case '3': + if (*flags & XT_SCTP_CHUNK_TYPES) + exit_error(PARAMETER_PROBLEM, + "Only one `--chunk-types' allowed"); + check_inverse(optarg, &invert, &optind, 0); + + if (!argv[optind] + || argv[optind][0] == '-' || argv[optind][0] == '!') + exit_error(PARAMETER_PROBLEM, + "--chunk-types requires two args"); + + einfo->flags |= XT_SCTP_CHUNK_TYPES; + parse_sctp_chunks(einfo, argv[optind-1], argv[optind]); + if (invert) + einfo->invflags |= XT_SCTP_CHUNK_TYPES; + optind++; + *flags |= XT_SCTP_CHUNK_TYPES; + break; + + default: + return 0; + } + return 1; +} + +static void +final_check(unsigned int flags) +{ +} + +static char * +port_to_service(int port) +{ + struct servent *service; + + if ((service = getservbyport(htons(port), "sctp"))) + return service->s_name; + + return NULL; +} + +static void +print_port(u_int16_t port, int numeric) +{ + char *service; + + if (numeric || (service = port_to_service(port)) == NULL) + printf("%u", port); + else + printf("%s", service); +} + +static void +print_ports(const char *name, u_int16_t min, u_int16_t max, + int invert, int numeric) +{ + const char *inv = invert ? "!" : ""; + + if (min != 0 || max != 0xFFFF || invert) { + printf("%s", name); + if (min == max) { + printf(":%s", inv); + print_port(min, numeric); + } else { + printf("s:%s", inv); + print_port(min, numeric); + printf(":"); + print_port(max, numeric); + } + printf(" "); + } +} + +static void +print_chunk_flags(u_int32_t chunknum, u_int8_t chunk_flags, u_int8_t chunk_flags_mask) +{ + int i; + + DEBUGP("type: %d\tflags: %x\tflag mask: %x\n", chunknum, chunk_flags, + chunk_flags_mask); + + if (chunk_flags_mask) { + printf(":"); + } + + for (i = 7; i >= 0; i--) { + if (chunk_flags_mask & (1 << i)) { + if (chunk_flags & (1 << i)) { + printf("%c", sctp_chunk_names[chunknum].valid_flags[7-i]); + } else { + printf("%c", tolower(sctp_chunk_names[chunknum].valid_flags[7-i])); + } + } + } +} + +static void +print_chunk(u_int32_t chunknum, int numeric) +{ + if (numeric) { + printf("0x%04X", chunknum); + } + else { + int i; + + for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) { + if (sctp_chunk_names[i].chunk_type == chunknum) + printf("%s", sctp_chunk_names[chunknum].name); + } + } +} + +static void +print_chunks(u_int32_t chunk_match_type, + const u_int32_t *chunkmap, + const struct xt_sctp_flag_info *flag_info, + int flag_count, + int numeric) +{ + int i, j; + int flag; + + switch (chunk_match_type) { + case SCTP_CHUNK_MATCH_ANY: printf("any "); break; + case SCTP_CHUNK_MATCH_ALL: printf("all "); break; + case SCTP_CHUNK_MATCH_ONLY: printf("only "); break; + default: printf("Never reach herer\n"); break; + } + + if (SCTP_CHUNKMAP_IS_CLEAR(chunkmap)) { + printf("NONE "); + goto out; + } + + if (SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)) { + printf("ALL "); + goto out; + } + + flag = 0; + for (i = 0; i < 256; i++) { + if (SCTP_CHUNKMAP_IS_SET(chunkmap, i)) { + if (flag) + printf(","); + flag = 1; + print_chunk(i, numeric); + for (j = 0; j < flag_count; j++) { + if (flag_info[j].chunktype == i) { + print_chunk_flags(i, flag_info[j].flag, + flag_info[j].flag_mask); + } + } + } + } + + if (flag) + printf(" "); +out: + return; +} + +/* Prints out the matchinfo. */ +static void +print(const void *ip, + const struct xt_entry_match *match, + int numeric) +{ + const struct xt_sctp_info *einfo = + (const struct xt_sctp_info *)match->data; + + printf("sctp "); + + if (einfo->flags & XT_SCTP_SRC_PORTS) { + print_ports("spt", einfo->spts[0], einfo->spts[1], + einfo->invflags & XT_SCTP_SRC_PORTS, + numeric); + } + + if (einfo->flags & XT_SCTP_DEST_PORTS) { + print_ports("dpt", einfo->dpts[0], einfo->dpts[1], + einfo->invflags & XT_SCTP_DEST_PORTS, + numeric); + } + + if (einfo->flags & XT_SCTP_CHUNK_TYPES) { + /* FIXME: print_chunks() is used in save() where the printing of '!' + s taken care of, so we need to do that here as well */ + if (einfo->invflags & XT_SCTP_CHUNK_TYPES) { + printf("! "); + } + print_chunks(einfo->chunk_match_type, einfo->chunkmap, + einfo->flag_info, einfo->flag_count, numeric); + } +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void +save(const void *ip, + const struct xt_entry_match *match) +{ + const struct xt_sctp_info *einfo = + (const struct xt_sctp_info *)match->data; + + if (einfo->flags & XT_SCTP_SRC_PORTS) { + if (einfo->invflags & XT_SCTP_SRC_PORTS) + printf("! "); + if (einfo->spts[0] != einfo->spts[1]) + printf("--sport %u:%u ", + einfo->spts[0], einfo->spts[1]); + else + printf("--sport %u ", einfo->spts[0]); + } + + if (einfo->flags & XT_SCTP_DEST_PORTS) { + if (einfo->invflags & XT_SCTP_DEST_PORTS) + printf("! "); + if (einfo->dpts[0] != einfo->dpts[1]) + printf("--dport %u:%u ", + einfo->dpts[0], einfo->dpts[1]); + else + printf("--dport %u ", einfo->dpts[0]); + } + + if (einfo->flags & XT_SCTP_CHUNK_TYPES) { + if (einfo->invflags & XT_SCTP_CHUNK_TYPES) + printf("! "); + printf("--chunk-types "); + + print_chunks(einfo->chunk_match_type, einfo->chunkmap, + einfo->flag_info, einfo->flag_count, 0); + } +} + +static struct xtables_match sctp = { + .name = "sctp", + .family = AF_INET, + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_sctp_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_sctp_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +static struct xtables_match sctp6 = { + .name = "sctp", + .family = AF_INET6, + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_sctp_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_sctp_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + xtables_register_match(&sctp); + xtables_register_match(&sctp6); +} + diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h new file mode 100644 index 0000000..b157897 --- /dev/null +++ b/include/linux/netfilter/xt_sctp.h @@ -0,0 +1,107 @@ +#ifndef _XT_SCTP_H_ +#define _XT_SCTP_H_ + +#define XT_SCTP_SRC_PORTS 0x01 +#define XT_SCTP_DEST_PORTS 0x02 +#define XT_SCTP_CHUNK_TYPES 0x04 + +#define XT_SCTP_VALID_FLAGS 0x07 + +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0])) + + +struct xt_sctp_flag_info { + u_int8_t chunktype; + u_int8_t flag; + u_int8_t flag_mask; +}; + +#define XT_NUM_SCTP_FLAGS 4 + +struct xt_sctp_info { + u_int16_t dpts[2]; /* Min, Max */ + u_int16_t spts[2]; /* Min, Max */ + + u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */ + +#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */ +#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */ +#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */ + + u_int32_t chunk_match_type; + struct xt_sctp_flag_info flag_info[XT_NUM_SCTP_FLAGS]; + int flag_count; + + u_int32_t flags; + u_int32_t invflags; +}; + +#define bytes(type) (sizeof(type) * 8) + +#define SCTP_CHUNKMAP_SET(chunkmap, type) \ + do { \ + chunkmap[type / bytes(u_int32_t)] |= \ + 1 << (type % bytes(u_int32_t)); \ + } while (0) + +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ + do { \ + chunkmap[type / bytes(u_int32_t)] &= \ + ~(1 << (type % bytes(u_int32_t))); \ + } while (0) + +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ +({ \ + (chunkmap[type / bytes (u_int32_t)] & \ + (1 << (type % bytes (u_int32_t)))) ? 1: 0; \ +}) + +#define SCTP_CHUNKMAP_RESET(chunkmap) \ + do { \ + int i; \ + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ + chunkmap[i] = 0; \ + } while (0) + +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \ + do { \ + int i; \ + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ + chunkmap[i] = ~0; \ + } while (0) + +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \ + do { \ + int i; \ + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ + destmap[i] = srcmap[i]; \ + } while (0) + +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \ +({ \ + int i; \ + int flag = 1; \ + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \ + if (chunkmap[i]) { \ + flag = 0; \ + break; \ + } \ + } \ + flag; \ +}) + +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \ +({ \ + int i; \ + int flag = 1; \ + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \ + if (chunkmap[i] != ~0) { \ + flag = 0; \ + break; \ + } \ + } \ + flag; \ +}) + +#endif /* _XT_SCTP_H_ */ + diff --git a/include/linux/netfilter_ipv4/ipt_sctp.h b/include/linux/netfilter_ipv4/ipt_sctp.h deleted file mode 100644 index e93a9ec..0000000 --- a/include/linux/netfilter_ipv4/ipt_sctp.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _IPT_SCTP_H_ -#define _IPT_SCTP_H_ - -#define IPT_SCTP_SRC_PORTS 0x01 -#define IPT_SCTP_DEST_PORTS 0x02 -#define IPT_SCTP_CHUNK_TYPES 0x04 - -#define IPT_SCTP_VALID_FLAGS 0x07 - -#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0])) - - -struct ipt_sctp_flag_info { - u_int8_t chunktype; - u_int8_t flag; - u_int8_t flag_mask; -}; - -#define IPT_NUM_SCTP_FLAGS 4 - -struct ipt_sctp_info { - u_int16_t dpts[2]; /* Min, Max */ - u_int16_t spts[2]; /* Min, Max */ - - u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */ - -#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */ -#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */ -#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */ - - u_int32_t chunk_match_type; - struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS]; - int flag_count; - - u_int32_t flags; - u_int32_t invflags; -}; - -#define bytes(type) (sizeof(type) * 8) - -#define SCTP_CHUNKMAP_SET(chunkmap, type) \ - do { \ - chunkmap[type / bytes(u_int32_t)] |= \ - 1 << (type % bytes(u_int32_t)); \ - } while (0) - -#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ - do { \ - chunkmap[type / bytes(u_int32_t)] &= \ - ~(1 << (type % bytes(u_int32_t))); \ - } while (0) - -#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ -({ \ - (chunkmap[type / bytes (u_int32_t)] & \ - (1 << (type % bytes (u_int32_t)))) ? 1: 0; \ -}) - -#define SCTP_CHUNKMAP_RESET(chunkmap) \ - do { \ - int i; \ - for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ - chunkmap[i] = 0; \ - } while (0) - -#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \ - do { \ - int i; \ - for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ - chunkmap[i] = ~0; \ - } while (0) - -#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \ - do { \ - int i; \ - for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ - destmap[i] = srcmap[i]; \ - } while (0) - -#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \ -({ \ - int i; \ - int flag = 1; \ - for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \ - if (chunkmap[i]) { \ - flag = 0; \ - break; \ - } \ - } \ - flag; \ -}) - -#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \ -({ \ - int i; \ - int flag = 1; \ - for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \ - if (chunkmap[i] != ~0) { \ - flag = 0; \ - break; \ - } \ - } \ - flag; \ -}) - -#endif /* _IPT_SCTP_H_ */ - -- cgit v1.2.3