summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CURRENT_ISSUES6
-rw-r--r--extensions/Makefile2
-rw-r--r--extensions/libipt_sctp.c301
-rw-r--r--include/linux/netfilter_ipv4/ipt_sctp.h111
-rw-r--r--iptables-save.c1
-rw-r--r--iptables.c1
6 files changed, 272 insertions, 150 deletions
diff --git a/CURRENT_ISSUES b/CURRENT_ISSUES
index 181c83a..cdec36f 100644
--- a/CURRENT_ISSUES
+++ b/CURRENT_ISSUES
@@ -15,8 +15,6 @@ SLOG target
- needs to be integrated with recent nfnetlink/ctnetlink
loop detection / nf_hipac (mail from dec 15
- need time
-reject --with-admin-prohibited
- - most compatible version needs to be used
IPv6 REJECT target fix
- important, it's a pity that it's still broken
bi-directional ftp state tracking
@@ -28,9 +26,5 @@ expectations allegedly don't work on sparc64
- is this in bugzilla yet?
new bytelimit match
- unify it with 'limit' for 2.5.x
-new hash (abcdx/...) for conntrack
- - put patch in p-o-m, do testing, submit to kernel
-PPTP reverse key lookup <3E40CA1F.1080205@snapgear.com>
- - ?
boolean MARK operations
- patch by Anders Fugmann, needs 64bit testing
diff --git a/extensions/Makefile b/extensions/Makefile
index 2a45ea0..17a1c00 100644
--- a/extensions/Makefile
+++ b/extensions/Makefile
@@ -5,7 +5,7 @@
# header files are present in the include/linux directory of this iptables
# package (HW)
#
-PF_EXT_SLIB:=ah connlimit connmark conntrack dscp ecn esp helper icmp iprange length limit mac mark multiport owner physdev pkttype realm rpc standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
+PF_EXT_SLIB:=ah connlimit connmark conntrack dscp ecn esp helper icmp iprange length limit mac mark multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner standard tcp udp HL LOG MARK TRACE
# Optionals
diff --git a/extensions/libipt_sctp.c b/extensions/libipt_sctp.c
index d512fa6..d47719f 100644
--- a/extensions/libipt_sctp.c
+++ b/extensions/libipt_sctp.c
@@ -17,25 +17,41 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_sctp.h>
+#if 0
+#define DEBUGP(format, first...) printf(format, ##first)
+#define static
+#else
+#define DEBUGP(format, fist...)
+#endif
+
+/*static void
+print_chunks(u_int32_t chunk_match_type, const u_int32_t *chunkmap, int numeric);*/
+
/* Initialize the match. */
static void
-init(struct ipt_entry_match *m, unsigned int *nfcache)
+init(struct ipt_entry_match *m,
+ unsigned int *nfcache)
{
struct ipt_sctp_info *einfo = (struct ipt_sctp_info *)m->data;
+ einfo->flags = einfo->invflags = 0;
+
+ /*einfo->spts[0] = einfo->dpts[0] = 0;
einfo->spts[1] = einfo->dpts[1] = 0xFFFF;
+ SCTP_CHUNKMAP_RESET(einfo->chunkmap);*/
}
-static void help(void)
+static void help(void)
{
printf(
"SCTP match v%s options\n"
-" --sctp-chunks [!] mask comp match when SCTP chunks & mask == comp\n"
-" --source-port [!] port[:port]\n"
+" --source-port [!] port[:port] match source port(s)\n"
" --sport ...\n"
-" match source port(s)"
-" --destination-port [!] port[:port]\n"
-" --dport ...\n\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);
}
@@ -44,7 +60,7 @@ static struct option opts[] = {
{ .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 = "sctp-chunks", .has_arg = 1, .flag = 0, .val = '3' },
+ { .name = "chunk-types", .has_arg = 1, .flag = 0, .val = '3' },
{ .name = 0 }
};
@@ -64,24 +80,27 @@ parse_sctp_port(const char *port)
{
unsigned int portnum;
+ DEBUGP("%s\n", port);
if (string_to_number(port, 0, 65535, &portnum) != -1 ||
(portnum = service_to_port(port)) != -1)
return (u_int16_t)portnum;
exit_error(PARAMETER_PROBLEM,
- "invalid TCP port/service `%s' specified", port);
+ "invalid SCTP port/service `%s' specified", port);
}
-
static void
-parse_sctp_ports(const char *portstring, u_int16_t *ports)
+parse_sctp_ports(const char *portstring,
+ u_int16_t *ports)
{
char *buffer;
char *cp;
buffer = strdup(portstring);
- if ((cp = strchr(buffer, ':')) == NULL)
+ DEBUGP("%s\n", portstring);
+ if ((cp = strchr(buffer, ':')) == NULL) {
ports[0] = ports[1] = parse_sctp_port(buffer);
+ }
else {
*cp = '\0';
cp++;
@@ -98,51 +117,62 @@ parse_sctp_ports(const char *portstring, u_int16_t *ports)
struct sctp_chunk_names {
const char *name;
- unsigned int flag;
+ unsigned int chunk_type;
};
-/* FIXME: */
-#define ALL_CHUNKS 0xabcdef
+/*'ALL' and 'NONE' will be treated specially. */
static struct sctp_chunk_names sctp_chunk_names[]
-= { { .name = "DATA", .flag = (1 << 0) },
- { .name = "INIT", .flag = (1 << 1) },
- { .name = "INIT_ACK", .flag = (1 << 2) },
- { .name = "SACK", .flag = (1 << 3) },
- { .name = "HEARTBEAT", .flag = (1 << 4) },
- { .name = "HEARTBEAT_ACK", .flag = (1 << 5) },
- { .name = "ABORT", .flag = (1 << 6) },
- { .name = "SHUTDOWN", .flag = (1 << 7) },
- { .name = "SHUTDOWN_ACK", .flag = (1 << 8) },
- { .name = "ERROR", .flag = (1 << 9) },
- { .name = "COOKIE_ECHO", .flag = (1 << 10) },
- { .name = "COOKIE_ACK", .flag = (1 << 11) },
- { .name = "ECN_ECNE", .flag = (1 << 12) },
- { .name = "ECN_CWR", .flag = (1 << 13) },
- { .name = "SHUTDOWN_COMPLETE", .flag = (1 << 14) },
- { .name = "ASCONF", .flag = (1 << 31) },
- { .name = "ASCONF_ACK", .flag = (1 << 30) },
- { .name = "ALL", .flag = ALL_CHUNKS },
- { .name = "NONE", .flag = 0 },
+= { { .name = "DATA", .chunk_type = 0 },
+ { .name = "INIT", .chunk_type = 1 },
+ { .name = "INIT_ACK", .chunk_type = 2 },
+ { .name = "SACK", .chunk_type = 3 },
+ { .name = "HEARTBEAT", .chunk_type = 4 },
+ { .name = "HEARTBEAT_ACK", .chunk_type = 5 },
+ { .name = "ABORT", .chunk_type = 6 },
+ { .name = "SHUTDOWN", .chunk_type = 7 },
+ { .name = "SHUTDOWN_ACK", .chunk_type = 8 },
+ { .name = "ERROR", .chunk_type = 9 },
+ { .name = "COOKIE_ECHO", .chunk_type = 10 },
+ { .name = "COOKIE_ACK", .chunk_type = 11 },
+ { .name = "ECN_ECNE", .chunk_type = 12 },
+ { .name = "ECN_CWR", .chunk_type = 13 },
+ { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14 },
+ { .name = "ASCONF", .chunk_type = 31 },
+ { .name = "ASCONF_ACK", .chunk_type = 30 },
};
-
-static unsigned int
-parse_sctp_chunk(const char *flags)
+static void
+parse_sctp_chunk(struct ipt_sctp_info *einfo,
+ const char *chunks)
{
- unsigned int ret = 0;
char *ptr;
char *buffer;
+ unsigned int i;
+ int found = 0;
+
+ buffer = strdup(chunks);
+ DEBUGP("Buffer: %s\n", buffer);
- buffer = strdup(flags);
+ 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, ",")) {
- unsigned int i;
- int found = 0;
- for (i = 0;
- i < sizeof(sctp_chunk_names)/sizeof(struct sctp_chunk_names);
- i++) {
+ found = 0;
+ DEBUGP("Next Chunk type %s\n", ptr);
+ for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) {
if (strcasecmp(sctp_chunk_names[i].name, ptr) == 0) {
- ret |= sctp_chunk_names[i].flag;
+ 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;
}
@@ -151,28 +181,31 @@ parse_sctp_chunk(const char *flags)
exit_error(PARAMETER_PROBLEM,
"Unknown sctp chunk `%s'", ptr);
}
-
+out:
free(buffer);
- return ret;
}
static void
parse_sctp_chunks(struct ipt_sctp_info *einfo,
- const char *mask,
- const char *cmp,
- int invert)
+ const char *match_type,
+ const char *chunks)
{
- einfo->chunks = parse_sctp_chunk(mask);
- einfo->chunk_mask = parse_sctp_chunk(cmp);
+ 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\"");
+ }
- if (invert)
- einfo->invflags |= IPT_SCTP_INV_CHUNKS;
+ SCTP_CHUNKMAP_RESET(einfo->chunkmap);
+ parse_sctp_chunk(einfo, chunks);
}
-#define SCTP_SRC_PORTS 0x01
-#define SCTP_DST_PORTS 0x02
-#define SCTP_CHUNKS 0x03
-
static int
parse(int c, char **argv, int invert, unsigned int *flags,
const struct ipt_entry *entry,
@@ -184,48 +217,53 @@ parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) {
case '1':
- if (*flags & SCTP_SRC_PORTS)
+ 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_INV_SRCPT;
- *flags |= SCTP_SRC_PORTS;
+ einfo->invflags |= IPT_SCTP_SRC_PORTS;
+ *flags |= IPT_SCTP_SRC_PORTS;
*nfcache |= NFC_IP_SRC_PT;
break;
case '2':
- if (*flags & SCTP_DST_PORTS)
+ 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_INV_DSTPT;
- *flags |= SCTP_DST_PORTS;
+ einfo->invflags |= IPT_SCTP_DEST_PORTS;
+ *flags |= IPT_SCTP_DEST_PORTS;
*nfcache |= NFC_IP_DST_PT;
break;
case '3':
- if (*flags & SCTP_CHUNKS)
+ if (*flags & IPT_SCTP_CHUNK_TYPES)
exit_error(PARAMETER_PROBLEM,
- "Only one `--sctp-chunks' allowed");
+ "Only one `--chunk-types' allowed");
check_inverse(optarg, &invert, &optind, 0);
if (!argv[optind]
|| argv[optind][0] == '-' || argv[optind][0] == '!')
exit_error(PARAMETER_PROBLEM,
- "--sctp-chunks requires two args");
+ "--chunk-types requires two args");
- parse_sctp_chunks(einfo, argv[optind-1], argv[optind], invert);
+ 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 |= SCTP_CHUNKS;
+ *flags |= IPT_SCTP_CHUNK_TYPES;
break;
+
default:
return 0;
}
-
return 1;
}
@@ -278,41 +316,53 @@ print_ports(const char *name, u_int16_t min, u_int16_t max,
}
static void
-print_chunk(u_int32_t chunks)
+print_chunk(u_int32_t chunknum, int numeric)
{
- unsigned int have_flag = 0;
-
- while (chunks) {
- unsigned int i;
-
- for (i = 0; (chunks & sctp_chunk_names[i].flag) == 0; i++);
-
- if (have_flag)
- printf(",");
- printf("%s", sctp_chunk_names[i].name);
- have_flag = 1;
-
- chunks &= ~sctp_chunk_names[i].flag;
+ if (numeric) {
+ printf("0x%04X", chunknum);
+ }
+ else {
+ printf("%s", sctp_chunk_names[chunknum].name);
}
-
- if (!have_flag)
- printf("NONE");
}
static void
-print_chunks(u_int32_t mask, u_int32_t cmp, int invert, int numeric)
+print_chunks(u_int32_t chunk_match_type,
+ const u_int32_t *chunkmap,
+ int numeric)
{
- if (mask || invert) {
- printf("flags:%s", invert ? "!" : "");
- if (numeric)
- printf("0x%04X/0x%04X ", mask, cmp);
- else {
- print_chunk(mask);
- printf("/");
- print_chunk(cmp);
- printf(" ");
+ int i;
+ 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)) {
+ flag && printf(",");
+ flag = 1;
+ print_chunk(i, numeric);
}
}
+
+ flag && printf(" ");
+out:
+ return;
}
/* Prints out the matchinfo. */
@@ -326,28 +376,38 @@ print(const struct ipt_ip *ip,
printf("sctp ");
- print_ports("spt", einfo->spts[0], einfo->spts[1],
- einfo->invflags & IPT_SCTP_INV_SRCPT,
- numeric);
- print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
- einfo->invflags & IPT_SCTP_INV_DSTPT,
- numeric);
+ 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);
+ }
- print_chunks(einfo->chunks, einfo->chunk_mask,
- einfo->invflags & ~IPT_SCTP_INV_MASK,
- 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, numeric);
+ }
}
/* Saves the union ipt_matchinfo in parsable form to stdout. */
static void
-save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+save(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match)
{
const struct ipt_sctp_info *einfo =
(const struct ipt_sctp_info *)match->data;
- if (einfo->spts[0] != 0
- || einfo->spts[1] != 0xFFFF) {
- if (einfo->invflags & IPT_SCTP_INV_SRCPT)
+ 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 ",
@@ -356,9 +416,8 @@ save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
printf("--sport %u ", einfo->spts[0]);
}
- if (einfo->dpts[0] != 0
- || einfo->dpts[1] != 0xFFFF) {
- if (einfo->invflags & IPT_SCTP_INV_DSTPT)
+ 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 ",
@@ -367,17 +426,12 @@ save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
printf("--dport %u ", einfo->dpts[0]);
}
- if (einfo->chunks
- || (einfo->invflags & IPT_SCTP_INV_CHUNKS)) {
- if (einfo->invflags & IPT_SCTP_INV_CHUNKS)
+ if (einfo->flags & IPT_SCTP_CHUNK_TYPES) {
+ if (einfo->invflags & IPT_SCTP_CHUNK_TYPES)
printf("! ");
- printf("--sctp-chunks ");
- if (einfo->chunks != ALL_CHUNKS) {
- print_chunk(einfo->chunks);
- }
- printf(" ");
- print_chunk(einfo->chunk_mask);
- printf(" ");
+ printf("--chunk-types ");
+
+ print_chunks(einfo->chunk_match_type, einfo->chunkmap, 0);
}
}
@@ -400,3 +454,4 @@ void _init(void)
{
register_match(&sctp);
}
+
diff --git a/include/linux/netfilter_ipv4/ipt_sctp.h b/include/linux/netfilter_ipv4/ipt_sctp.h
index 54c58fa..575c672 100644
--- a/include/linux/netfilter_ipv4/ipt_sctp.h
+++ b/include/linux/netfilter_ipv4/ipt_sctp.h
@@ -1,25 +1,96 @@
-/* iptables module for matching the SCTP header
- *
- * (C) 2003 Harald Welte <laforge@gnumonks.org>
- *
- * This software is distributed under GNU GPL v2, 1991
- *
- * $Id$
- */
-#ifndef _IPT_SCTP_H
-#define _IPT_SCTP_H
+#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_info {
- u_int16_t spts[2]; /* Souce port range */
- u_int16_t dpts[2]; /* Destination port range */
- u_int32_t chunks; /* chunks to be matched */
- u_int32_t chunk_mask; /* chunk mask to be matched */
- u_int8_t invflags; /* Inverse flags */
+ 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;
+
+ u_int32_t flags;
+ u_int32_t invflags;
};
-#define IPT_SCTP_INV_SRCPT 0x01 /* Invert the sense of source ports */
-#define IPT_SCTP_INV_DSTPT 0x02 /* Invert the sense of dest ports */
-#define IPT_SCTP_INV_CHUNKS 0x03 /* Invert the sense of chunks */
-#define IPT_SCTP_INV_MASK 0x03 /* All possible flags */
+#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_ */
-#endif /* _IPT_SCTP_H */
diff --git a/iptables-save.c b/iptables-save.c
index 41173ea..cdedfbf 100644
--- a/iptables-save.c
+++ b/iptables-save.c
@@ -75,6 +75,7 @@ static const struct pprot chain_protos[] = {
{ "icmp", IPPROTO_ICMP },
{ "esp", IPPROTO_ESP },
{ "ah", IPPROTO_AH },
+ { "sctp", IPPROTO_SCTP },
};
static void print_proto(u_int16_t proto, int invert)
diff --git a/iptables.c b/iptables.c
index 2c6282a..ae6538c 100644
--- a/iptables.c
+++ b/iptables.c
@@ -235,6 +235,7 @@ static const struct pprot chain_protos[] = {
{ "icmp", IPPROTO_ICMP },
{ "esp", IPPROTO_ESP },
{ "ah", IPPROTO_AH },
+ { "sctp", IPPROTO_SCTP },
{ "all", 0 },
};