[PATCH 4/9] libxt_TOS: use guided option parser

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Jan Engelhardt <jengelh@xxxxxxxxxx>
---
 extensions/libxt_TOS.c |  137 ++++++++++++++++++++----------------------------
 include/xtables.h.in   |    5 ++
 xtoptions.c            |   81 ++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 80 deletions(-)

diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c
index 58ff2fc..cef5876 100644
--- a/extensions/libxt_TOS.c
+++ b/extensions/libxt_TOS.c
@@ -2,7 +2,7 @@
  * Shared library add-on to iptables to add TOS target support
  *
  * Copyright © CC Computer Consultants GmbH, 2007
- * Contact: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>
+ * Contact: Jan Engelhardt <jengelh@xxxxxxxxxx>
  */
 #include <getopt.h>
 #include <stdbool.h>
@@ -20,20 +20,33 @@ struct ipt_tos_target_info {
 };
 
 enum {
-	FLAG_TOS = 1 << 0,
+	O_SET_TOS = 0,
+	O_AND_TOS,
+	O_OR_TOS,
+	O_XOR_TOS,
+	F_SET_TOS = 1 << O_SET_TOS,
+	F_AND_TOS = 1 << O_AND_TOS,
+	F_OR_TOS  = 1 << O_OR_TOS,
+	F_XOR_TOS = 1 << O_XOR_TOS,
+	F_ANY     = F_SET_TOS | F_AND_TOS | F_OR_TOS | F_XOR_TOS,
 };
 
-static const struct option tos_tg_opts_v0[] = {
-	{.name = "set-tos", .has_arg = true, .val = '='},
-	XT_GETOPT_TABLEEND,
+static const struct xt_option_entry tos_tg_opts_v0[] = {
+	{.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK,
+	 .excl = F_ANY, .max = 0xFF},
+	XTOPT_TABLEEND,
 };
 
-static const struct option tos_tg_opts[] = {
-	{.name = "set-tos", .has_arg = true, .val = '='},
-	{.name = "and-tos", .has_arg = true, .val = '&'},
-	{.name = "or-tos",  .has_arg = true, .val = '|'},
-	{.name = "xor-tos", .has_arg = true, .val = '^'},
-	XT_GETOPT_TABLEEND,
+static const struct xt_option_entry tos_tg_opts[] = {
+	{.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK,
+	 .excl = F_ANY, .max = 0x3F},
+	{.name = "and-tos", .id = O_AND_TOS, .type = XTTYPE_UINT8,
+	 .excl = F_ANY},
+	{.name = "or-tos", .id = O_OR_TOS, .type = XTTYPE_UINT8,
+	 .excl = F_ANY},
+	{.name = "xor-tos", .id = O_XOR_TOS, .type = XTTYPE_UINT8,
+	 .excl = F_ANY},
+	XTOPT_TABLEEND,
 };
 
 static void tos_tg_help_v0(void)
@@ -78,84 +91,48 @@ XTABLES_VERSION);
 );
 }
 
-static int tos_tg_parse_v0(int c, char **argv, int invert, unsigned int *flags,
-                           const void *entry, struct xt_entry_target **target)
+static void tos_tg_parse_v0(struct xt_option_call *cb)
 {
-	struct ipt_tos_target_info *info = (void *)(*target)->data;
-	struct tos_value_mask tvm;
-
-	switch (c) {
-	case '=':
-		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS);
-		xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert);
-		if (!tos_parse_symbolic(optarg, &tvm, 0xFF))
-			xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg);
-		if (tvm.mask != 0xFF)
-			xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel "
-			           "is too old to support anything besides "
-				   "/0xFF as a mask.");
-		info->tos = tvm.value;
-		*flags |= FLAG_TOS;
-		return true;
-	}
-
-	return false;
+	struct ipt_tos_target_info *info = cb->data;
+
+	xtables_option_parse(cb);
+	if (cb->val.tos_mask != 0xFF)
+		xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel "
+		           "is too old to support anything besides "
+			   "/0xFF as a mask.");
+	info->tos = cb->val.tos_value;
 }
 
-static int tos_tg_parse(int c, char **argv, int invert, unsigned int *flags,
-                         const void *entry, struct xt_entry_target **target)
+static void tos_tg_parse(struct xt_option_call *cb)
 {
-	struct xt_tos_target_info *info = (void *)(*target)->data;
-	struct tos_value_mask tvm;
-	unsigned int bits;
-
-	switch (c) {
-	case '=': /* --set-tos */
-		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS);
-		xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert);
-		if (!tos_parse_symbolic(optarg, &tvm, 0x3F))
-			xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg);
-		info->tos_value = tvm.value;
-		info->tos_mask  = tvm.mask;
-		break;
+	struct xt_tos_target_info *info = cb->data;
 
-	case '&': /* --and-tos */
-		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--and-tos", *flags & FLAG_TOS);
-		xtables_param_act(XTF_NO_INVERT, "TOS", "--and-tos", invert);
-		if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX))
-			xtables_param_act(XTF_BAD_VALUE, "TOS", "--and-tos", optarg);
+	xtables_option_parse(cb);
+	switch (cb->entry->id) {
+	case O_SET_TOS:
+		info->tos_value = cb->val.tos_value;
+		info->tos_mask  = cb->val.tos_mask;
+		break;
+	case O_AND_TOS:
 		info->tos_value = 0;
-		info->tos_mask  = ~bits;
+		info->tos_mask  = ~cb->val.u8;
 		break;
-
-	case '|': /* --or-tos */
-		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--or-tos", *flags & FLAG_TOS);
-		xtables_param_act(XTF_NO_INVERT, "TOS", "--or-tos", invert);
-		if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX))
-			xtables_param_act(XTF_BAD_VALUE, "TOS", "--or-tos", optarg);
-		info->tos_value = bits;
-		info->tos_mask  = bits;
+	case O_OR_TOS:
+		info->tos_value = cb->val.u8;
+		info->tos_mask  = cb->val.u8;
 		break;
-
-	case '^': /* --xor-tos */
-		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--xor-tos", *flags & FLAG_TOS);
-		xtables_param_act(XTF_NO_INVERT, "TOS", "--xor-tos", invert);
-		if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX))
-			xtables_param_act(XTF_BAD_VALUE, "TOS", "--xor-tos", optarg);
-		info->tos_value = bits;
+	case O_XOR_TOS:
+		info->tos_value = cb->val.u8;
 		info->tos_mask  = 0;
 		break;
 	}
-
-	*flags |= FLAG_TOS;
-	return true;
 }
 
-static void tos_tg_check(unsigned int flags)
+static void tos_tg_check(struct xt_fcheck_call *cb)
 {
-	if (flags == 0)
+	if (!(cb->xflags & F_ANY))
 		xtables_error(PARAMETER_PROBLEM,
-		           "TOS: The --set-tos parameter is required");
+		           "TOS: An action is required");
 }
 
 static void tos_tg_print_v0(const void *ip,
@@ -215,11 +192,11 @@ static struct xtables_target tos_tg_reg[] = {
 		.size          = XT_ALIGN(sizeof(struct xt_tos_target_info)),
 		.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
 		.help          = tos_tg_help_v0,
-		.parse         = tos_tg_parse_v0,
-		.final_check   = tos_tg_check,
 		.print         = tos_tg_print_v0,
 		.save          = tos_tg_save_v0,
-		.extra_opts    = tos_tg_opts_v0,
+		.x6_parse      = tos_tg_parse_v0,
+		.x6_fcheck     = tos_tg_check,
+		.x6_options    = tos_tg_opts_v0,
 	},
 	{
 		.version       = XTABLES_VERSION,
@@ -229,11 +206,11 @@ static struct xtables_target tos_tg_reg[] = {
 		.size          = XT_ALIGN(sizeof(struct xt_tos_target_info)),
 		.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
 		.help          = tos_tg_help,
-		.parse         = tos_tg_parse,
-		.final_check   = tos_tg_check,
 		.print         = tos_tg_print,
 		.save          = tos_tg_save,
-		.extra_opts    = tos_tg_opts,
+		.x6_parse      = tos_tg_parse,
+		.x6_fcheck     = tos_tg_check,
+		.x6_options    = tos_tg_opts,
 	},
 };
 
diff --git a/include/xtables.h.in b/include/xtables.h.in
index a9a9ffa..b06ab61 100644
--- a/include/xtables.h.in
+++ b/include/xtables.h.in
@@ -50,6 +50,7 @@ struct in_addr;
  * %XTTYPE_UINT*:	standard integer
  * %XTTYPE_UINT*RC:	colon-separated range of standard integers
  * %XTTYPE_STRING:	arbitrary string
+ * %XTTYPE_TOSMASK:	8-bit TOS value with optional mask
  * %XTTYPE_MARKMASK32:	32-bit mark with optional mask
  * %XTTYPE_SYSLOGLEVEL:	syslog level by name or number
  * %XTTYPE_ONEHOST:	one host or address (union nf_inet_addr)
@@ -67,6 +68,7 @@ enum xt_option_type {
 	XTTYPE_UINT32RC,
 	XTTYPE_UINT64RC,
 	XTTYPE_STRING,
+	XTTYPE_TOSMASK,
 	XTTYPE_MARKMASK32,
 	XTTYPE_SYSLOGLEVEL,
 	XTTYPE_ONEHOST,
@@ -132,6 +134,9 @@ struct xt_option_call {
 		uint64_t u64, u64_range[2];
 		union nf_inet_addr inetaddr;
 		struct {
+			uint8_t tos_value, tos_mask;
+		};
+		struct {
 			uint32_t mark, mask;
 		};
 	} val;
diff --git a/xtoptions.c b/xtoptions.c
index 8478d26..69e43e9 100644
--- a/xtoptions.c
+++ b/xtoptions.c
@@ -19,8 +19,12 @@
 #include <string.h>
 #include <syslog.h>
 #include <arpa/inet.h>
+#include <netinet/ip.h>
 #include "xtables.h"
 #include "xshared.h"
+#ifndef IPTOS_NORMALSVC
+#	define IPTOS_NORMALSVC 0
+#endif
 
 #define XTOPT_MKPTR(cb) \
 	((void *)((char *)(cb)->data + (cb)->entry->ptroff))
@@ -33,6 +37,10 @@ struct syslog_level {
 	uint8_t level;
 };
 
+struct tos_value_mask {
+	uint8_t value, mask;
+};
+
 /**
  * Creates getopt options from the x6-style option map, and assigns each a
  * getopt id.
@@ -232,6 +240,78 @@ static void xtopt_parse_string(struct xt_option_call *cb)
 	p[z] = '\0';
 }
 
+static const struct tos_symbol_info {
+	unsigned char value;
+	const char *name;
+} tos_symbol_names[] = {
+	{IPTOS_LOWDELAY,    "Minimize-Delay"},
+	{IPTOS_THROUGHPUT,  "Maximize-Throughput"},
+	{IPTOS_RELIABILITY, "Maximize-Reliability"},
+	{IPTOS_MINCOST,     "Minimize-Cost"},
+	{IPTOS_NORMALSVC,   "Normal-Service"},
+	{},
+};
+
+/*
+ * tos_parse_numeric - parse a string like "15/255"
+ *
+ * @str:	input string
+ * @tvm:	(value/mask) tuple
+ * @max:	maximum allowed value (must be pow(2,some_int)-1)
+ */
+static bool tos_parse_numeric(const char *str, struct xt_option_call *cb,
+                              unsigned int max)
+{
+	unsigned int value;
+	char *end;
+
+	xtables_strtoui(str, &end, &value, 0, max);
+	cb->val.tos_value = value;
+	cb->val.tos_mask  = max;
+
+	if (*end == '/') {
+		const char *p = end + 1;
+
+		if (!xtables_strtoui(p, &end, &value, 0, max))
+			xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"",
+			           str);
+		cb->val.tos_mask = value;
+	}
+
+	if (*end != '\0')
+		xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", str);
+	return true;
+}
+
+/**
+ * @str:	input string
+ * @tvm:	(value/mask) tuple
+ * @def_mask:	mask to force when a symbolic name is used
+ */
+static void xtopt_parse_tosmask(struct xt_option_call *cb)
+{
+	const struct tos_symbol_info *symbol;
+	char *tmp;
+
+	if (xtables_strtoui(cb->arg, &tmp, NULL, 0, UINT8_MAX)) {
+		tos_parse_numeric(cb->arg, cb, UINT8_MAX);
+		return;
+	}
+	/*
+	 * This is our way we deal with different defaults
+	 * for different revisions.
+	 */
+	cb->val.tos_mask = cb->entry->max;
+	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+		if (strcasecmp(cb->arg, symbol->name) == 0) {
+			cb->val.tos_value = symbol->value;
+			return;
+		}
+
+	xtables_error(PARAMETER_PROBLEM, "Symbolic name \"%s\" is unknown",
+		      cb->arg);
+}
+
 /**
  * Validate the input for being conformant to "mark[/mask]".
  */
@@ -413,6 +493,7 @@ static void (*const xtopt_subparse[])(struct xt_option_call *) = {
 	[XTTYPE_UINT32RC]    = xtopt_parse_mint,
 	[XTTYPE_UINT64RC]    = xtopt_parse_mint,
 	[XTTYPE_STRING]      = xtopt_parse_string,
+	[XTTYPE_TOSMASK]     = xtopt_parse_tosmask,
 	[XTTYPE_MARKMASK32]  = xtopt_parse_markmask,
 	[XTTYPE_SYSLOGLEVEL] = xtopt_parse_sysloglevel,
 	[XTTYPE_ONEHOST]     = xtopt_parse_onehost,
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux