From a51b16097b1e14cd13534d71eaae93d90a75fd50 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 8 Mar 2009 23:38:12 +0100 Subject: [PATCH 1/2] Add a reworked IPv4 options match - xt_ipv4options This revision 1 of ipv4options makes it possible to match the presence or absence of any of the 32 possible IP options, either all or any of the options the user specified. --- extensions/Kbuild | 1 + extensions/Mbuild | 1 + extensions/libxt_ipv4options.c | 177 +++++++++++++++++++++++++++++++++ extensions/xt_ipv4options.c | 72 ++++++++++++++ extensions/xt_ipv4options.h | 26 +++++ mconfig | 1 + 6 files changed, 278 insertions(+) create mode 100644 extensions/libxt_ipv4options.c create mode 100644 extensions/xt_ipv4options.c create mode 100644 extensions/xt_ipv4options.h diff --git a/extensions/Kbuild b/extensions/Kbuild index 7be640f..b50308a 100644 --- a/extensions/Kbuild +++ b/extensions/Kbuild @@ -19,6 +19,7 @@ obj-${build_fuzzy} += xt_fuzzy.o obj-${build_geoip} += xt_geoip.o obj-${build_ipp2p} += xt_ipp2p.o obj-${build_ipset} += ipset/ +obj-${build_ipv4options} += xt_ipv4options.o obj-${build_length2} += xt_length2.o obj-${build_lscan} += xt_lscan.o obj-${build_quota2} += xt_quota2.o diff --git a/extensions/Mbuild b/extensions/Mbuild index c25d927..feaca7b 100644 --- a/extensions/Mbuild +++ b/extensions/Mbuild @@ -12,6 +12,7 @@ obj-${build_fuzzy} += libxt_fuzzy.so obj-${build_geoip} += libxt_geoip.so obj-${build_ipp2p} += libxt_ipp2p.so obj-${build_ipset} += ipset/ +obj-${build_ipv4options} += libxt_ipv4options.so obj-${build_length2} += libxt_length2.so obj-${build_lscan} += libxt_lscan.so obj-${build_quota2} += libxt_quota2.so diff --git a/extensions/libxt_ipv4options.c b/extensions/libxt_ipv4options.c new file mode 100644 index 0000000..86244cd --- /dev/null +++ b/extensions/libxt_ipv4options.c @@ -0,0 +1,177 @@ +/* + * "ipv4options" match extension for iptables + * Coprygith © Jan Engelhardt, 2009 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License; either + * version 2 of the License, or any later version, as published by the + * Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include "xt_ipv4options.h" + +/* + * Overview from http://www.networksorcery.com/enp/protocol/ip.htm + * Not providing strings for options that seem to be most distant in the past. + */ +static const char *const v4opt_names[32] = { + [ 1] = "nop", + [ 2] = "security", /* RFC 1108 */ + [ 3] = "lsrr", /* RFC 791 */ + [ 4] = "timestamp", /* RFC 781, 791 */ + [ 7] = "record-route", /* RFC 791 */ + [ 9] = "ssrr", /* RFC 791 */ + [11] = "mtu-probe", /* RFC 1063 */ + [12] = "mtu-reply", /* RFC 1063 */ + [18] = "traceroute", /* RFC 1393 */ + [20] = "router-alert", /* RFC 2113 */ +}; + +static void ipv4options_mt_help(void) +{ + printf( +"ipv4options match options:\n" +"--flags [!]symbol[,...] Match presence/absence (!) of option\n" +" (either by name or number)\n" +"--any Interpret --flags as OR-combined\n\n"); +} + +static const struct option ipv4options_mt_opts[] = { + {.name = "flags", .has_arg = true, .val = 'f'}, + {.name = "any", .has_arg = false, .val = 'a'}, + {NULL}, +}; + +static void ipv4options_parse_flagspec(struct xt_ipv4options_mtinfo1 *info, + char *arg) +{ + unsigned int i, opt; + bool inv; + char *p; + + while (true) { + p = strchr(arg, ','); + if (p != NULL) + *p = '\0'; + + inv = false; + opt = 0; + if (*arg == '!') { + inv = true; + ++arg; + } + + for (i = 1; i < 32;++i) + if (v4opt_names[i] != NULL && + strcmp(v4opt_names[i], arg) == 0) { + opt = i; + break; + } + + if (opt == 0 && + !strtonum(arg, NULL, &opt, 0, UINT8_MAX)) + exit_error(PARAMETER_PROBLEM, + "ipv4options: Bad option value \"%s\"", arg); + + if (opt == 0) + exit_error(PARAMETER_PROBLEM, + "ipv4options: Option value may not be zero"); + + info->map |= (1 << opt); + if (inv) + info->invert |= (1 << opt); + if (p == NULL) + break; + arg = p + 1; + } +} + +static int ipv4options_mt_parse(int c, char **argv, int invert, + unsigned int *flags, const void *entry, struct xt_entry_match **match) +{ + struct xt_ipv4options_mtinfo1 *info = (void *)(*match)->data; + + switch (c) { + case 'a': /* --any */ + param_act(P_NO_INVERT, "ipv4options", "--any", invert); + info->flags |= XT_V4OPTS_ANY; + return true; + case 'f': /* --flags */ + param_act(P_NO_INVERT, "ipv4options", "--flags", invert); + ipv4options_parse_flagspec(info, optarg); + return true; + } + + return false; +} + +/* no checking of *flags - no IPv4 options is also valid */ + +static void ipv4options_print_flags(const struct xt_ipv4options_mtinfo1 *info, + bool numeric) +{ + uint32_t tmp = info->map; + unsigned int i; + + for (i = 1; i < 32; ++i) + if (tmp & (1 << i)) { + if (info->invert & (1 << i)) + printf("!"); + if (!numeric && v4opt_names[i] != NULL) + printf("%s", v4opt_names[i]); + else + printf("%u", i); + tmp &= ~(1 << i); + if (tmp) + printf(","); + } +} + +static void ipv4options_mt_print(const void *ip, + const struct xt_entry_match *match, int numeric) +{ + const struct xt_ipv4options_mtinfo1 *info = (void *)match->data; + + printf("ipv4options %s ", + (info->flags & XT_V4OPTS_ANY) ? "any-of" : "all-of"); + ipv4options_print_flags(info, numeric); + printf(" "); +} + +static void ipv4options_mt_save(const void *ip, + const struct xt_entry_match *match) +{ + const struct xt_ipv4options_mtinfo1 *info = (void *)match->data; + + if (info->map != 0) { + printf("--flags "); + ipv4options_print_flags(info, true); + } + if (info->flags & XT_V4OPTS_ANY) + printf(" --any"); + printf(" "); +} + +static struct xtables_match ipv4options_mt_reg = { + .version = XTABLES_VERSION, + .name = "ipv4options", + .revision = 1, + .family = PF_INET, + .size = XT_ALIGN(sizeof(struct xt_ipv4options_mtinfo1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ipv4options_mtinfo1)), + .help = ipv4options_mt_help, + .parse = ipv4options_mt_parse, + .print = ipv4options_mt_print, + .save = ipv4options_mt_save, + .extra_opts = ipv4options_mt_opts, +}; + +static __attribute__((constructor)) void ipv4options_mt_ldr(void) +{ + xtables_register_match(&ipv4options_mt_reg); +} diff --git a/extensions/xt_ipv4options.c b/extensions/xt_ipv4options.c new file mode 100644 index 0000000..f12fa3f --- /dev/null +++ b/extensions/xt_ipv4options.c @@ -0,0 +1,72 @@ +/* + * xt_ipv4opts - Netfilter module to match IPv4 options + * Copyright © Jan Engelhardt, 2009 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License; either + * version 2 of the License, or any later version, as published by the + * Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include "xt_ipv4options.h" +#include "compat_xtables.h" + +static uint32_t ipv4options_rd(const uint8_t *data, int len) +{ + uint32_t opts = 0; + + while (len >= 2) { + opts |= 1 << (data[0] & 0x1F); + len -= data[1]; + data += data[1]; + } + + return opts; +} + +static bool ipv4options_mt(const struct sk_buff *skb, + const struct xt_match_param *par) +{ + const struct xt_ipv4options_mtinfo1 *info = par->matchinfo; + const struct iphdr *iph = ip_hdr(skb); + uint32_t opts = 0; + uint16_t len = ip_hdrlen(skb) - sizeof(struct iphdr); + + if (len > 0) + opts = ipv4options_rd((const void *)iph + + sizeof(struct iphdr), len); + + opts ^= info->invert; + opts &= info->map; + return (info->flags & XT_V4OPTS_ANY) ? opts : opts == info->map; +} + +static struct xt_match ipv4options_mt_reg __read_mostly = { + .name = "ipv4options", + .revision = 1, + .family = NFPROTO_IPV4, + .match = ipv4options_mt, + .matchsize = XT_ALIGN(sizeof(struct xt_ipv4options_mtinfo1)), + .me = THIS_MODULE, +}; + +static int __init ipv4options_mt_init(void) +{ + return xt_register_match(&ipv4options_mt_reg); +} + +static void __exit ipv4options_mt_exit(void) +{ + xt_unregister_match(&ipv4options_mt_reg); +} + +MODULE_DESCRIPTION("Xatblse: IPv4 option match"); +MODULE_AUTHOR("Jan Engelhardt "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_ipv4options"); +module_init(ipv4options_mt_init); +module_exit(ipv4options_mt_exit); diff --git a/extensions/xt_ipv4options.h b/extensions/xt_ipv4options.h new file mode 100644 index 0000000..a7c5f23 --- /dev/null +++ b/extensions/xt_ipv4options.h @@ -0,0 +1,26 @@ +#ifndef _LINUX_NETFILTER_XT_IPV4OPTIONS_H +#define _LINUX_NETFILTER_XT_IPV4OPTIONS_H 1 + +/* IPv4 allows for a 5-bit option number - 32 options */ + +/** + * %XT_V4OPTS_ALL: all options in @map must be present (respecting @invert) + * %XT_V4OPTS_ANY: any of the option in @map + */ +enum xt_ipv4options_flags { + XT_V4OPTS_ALL = 1 << 0, + XT_V4OPTS_ANY = 1 << 1, +}; + +/** + * @map: bitmask of options that should appear + * @invert: inversion map + * @flags: see above + */ +struct xt_ipv4options_mtinfo1 { + __u32 map; + __u32 invert; + __u8 flags; +}; + +#endif /* _LINUX_NETFILTER_XT_IPV4OPTIONS_H */ diff --git a/mconfig b/mconfig index 27d7557..31990a6 100644 --- a/mconfig +++ b/mconfig @@ -14,6 +14,7 @@ build_fuzzy=m build_geoip=m build_ipp2p=m build_ipset=m +build_ipv4options=m build_length2=m build_lscan=m build_quota2=m From 8bd5fc14ba663625e8e60ecb4423e0fd550c38b8 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 11 Mar 2009 17:22:56 +0100 Subject: [PATCH 2/2] libxt_ipv4options: add manpage --- doc/changelog.txt | 3 ++ extensions/libxt_ipv4options.man | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 extensions/libxt_ipv4options.man diff --git a/doc/changelog.txt b/doc/changelog.txt index 39348a0..1575fbc 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,5 +1,8 @@ +- added a reworked ipv4options match + + Xtables-addons 1.12 (March 07 2009) =================================== - ipset: fix for compilation with 2.6.29-rt diff --git a/extensions/libxt_ipv4options.man b/extensions/libxt_ipv4options.man new file mode 100644 index 0000000..0628804 --- /dev/null +++ b/extensions/libxt_ipv4options.man @@ -0,0 +1,47 @@ +The "ipv4options" module allows to match against a set of IPv4 header options. +.TP +\fB\-\-flags\fP [\fB!\fP]\fIsymbol\fP[\fB,\fP[\fB!\fP]\fIsymbol...\fP] +Specify the options that shall appear or not appear in the header. Each +symbol specification is delimited by a comma, and a '!' can be prefixed to +a symbol to negate its presence. Symbols are either the name of an IPv4 option +or its number. See examples below. +.TP +\fB\-\-any\fP +By default, all of the flags specified must be present/absent, that is, they +form an AND condition. Use the \-\-any flag instead to use an OR condition +where only at least one symbol spec must be true. +.PP +Known symbol names (and their number): +.PP +1 - \fBnop\fP +.PP +2 - \fBsecurity\fP - RFC 1108 +.PP +3 - \fBlsrr\fP - Loose Source Routing, RFC 791 +.PP +4 - \fBtimestamp\fP - RFC 781, 791 +.PP +7 - \fBrecord\-route\fP - RFC 791 +.PP +9 - \fBssrr\fP - Strict Source Routing, RFC 791 +.PP +11 - \fBmtu\-probe\fP - RFC 1063 +.PP +12 - \fBmtu\-reply\fP - RFC 1063 +.PP +18 - \fBtraceroute\fP - RFC 1393 +.PP +20 - \fBrouter-alert\fP - RFC 2113 +.PP +Examples: +.PP +Match packets that have both Timestamp and NOP: +\-m ipv4options \-\-flags nop,timestamp +.PP +~ that have either of Timestamp or NOP, or both: +\-\-flags nop,timestamp \-\-any +.PP +~ that have Timestamp and no NOP: \-\-flags '!nop,timestamp' +.PP +~ that have either no NOP or a timestamp (or both conditions): +\-\-flags '!nop,timestamp' \-\-any