diff mbox series

[iptables,v2,09/17] nft-arp: Introduce post_parse callback

Message ID 20210930140419.6170-10-phil@nwl.cc
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series Eliminate dedicated arptables-nft parser | expand

Commit Message

Phil Sutter Sept. 30, 2021, 2:04 p.m. UTC
This accomplishes the same tasks as e.g. nft_ipv4_post_parse() plus some
arptables-specific bits.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft-arp.c     | 150 +++++++++++++++++++++++++++++++++++++++-
 iptables/nft-shared.h  |   3 +
 iptables/xtables-arp.c | 153 +++++++----------------------------------
 3 files changed, 178 insertions(+), 128 deletions(-)
diff mbox series

Patch

diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index fbaf1a6d52184..b37ffbb592023 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -546,6 +546,154 @@  static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
 	printf(":%s %s\n", chain, policy ?: "-");
 }
 
+static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
+{
+	char *dup = strdup(from);
+	char *p, *buffer;
+	int i, ret = -1;
+
+	if (!dup)
+		return -1;
+
+	if ( (p = strrchr(dup, '/')) != NULL) {
+		*p = '\0';
+		i = strtol(p+1, &buffer, 10);
+		if (*buffer != '\0' || i < 0 || i > 255)
+			goto out_err;
+		*mask = (uint8_t)i;
+	} else
+		*mask = 255;
+	i = strtol(dup, &buffer, 10);
+	if (*buffer != '\0' || i < 0 || i > 255)
+		goto out_err;
+	*to = (uint8_t)i;
+	ret = 0;
+out_err:
+	free(dup);
+	return ret;
+
+}
+
+static int get16_and_mask(const char *from, uint16_t *to,
+			  uint16_t *mask, int base)
+{
+	char *dup = strdup(from);
+	char *p, *buffer;
+	int i, ret = -1;
+
+	if (!dup)
+		return -1;
+
+	if ( (p = strrchr(dup, '/')) != NULL) {
+		*p = '\0';
+		i = strtol(p+1, &buffer, base);
+		if (*buffer != '\0' || i < 0 || i > 65535)
+			goto out_err;
+		*mask = htons((uint16_t)i);
+	} else
+		*mask = 65535;
+	i = strtol(dup, &buffer, base);
+	if (*buffer != '\0' || i < 0 || i > 65535)
+		goto out_err;
+	*to = htons((uint16_t)i);
+	ret = 0;
+out_err:
+	free(dup);
+	return ret;
+}
+
+static void nft_arp_post_parse(int command,
+			       struct iptables_command_state *cs,
+			       struct xtables_args *args)
+{
+	cs->arp.arp.invflags = args->invflags;
+
+	memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
+	memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
+
+	memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
+	memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
+
+	cs->arp.counters.pcnt = args->pcnt_cnt;
+	cs->arp.counters.bcnt = args->bcnt_cnt;
+
+	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
+		if (!(cs->options & OPT_DESTINATION))
+			args->dhostnetworkmask = "0.0.0.0/0";
+		if (!(cs->options & OPT_SOURCE))
+			args->shostnetworkmask = "0.0.0.0/0";
+	}
+
+	if (args->shostnetworkmask)
+		xtables_ipparse_multiple(args->shostnetworkmask,
+					 &args->s.addr.v4, &args->s.mask.v4,
+					 &args->s.naddrs);
+	if (args->dhostnetworkmask)
+		xtables_ipparse_multiple(args->dhostnetworkmask,
+					 &args->d.addr.v4, &args->d.mask.v4,
+					 &args->d.naddrs);
+
+	if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+	    (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+		xtables_error(PARAMETER_PROBLEM,
+			      "! not allowed with multiple"
+			      " source or destination IP addresses");
+
+	if (args->src_mac &&
+	    xtables_parse_mac_and_mask(args->src_mac,
+				       cs->arp.arp.src_devaddr.addr,
+				       cs->arp.arp.src_devaddr.mask))
+		xtables_error(PARAMETER_PROBLEM,
+			      "Problem with specified source mac");
+	if (args->dst_mac &&
+	    xtables_parse_mac_and_mask(args->dst_mac,
+				       cs->arp.arp.tgt_devaddr.addr,
+				       cs->arp.arp.tgt_devaddr.mask))
+		xtables_error(PARAMETER_PROBLEM,
+			      "Problem with specified destination mac");
+	if (args->arp_hlen) {
+		getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
+				   &cs->arp.arp.arhln_mask);
+
+		if (cs->arp.arp.arhln != 6)
+			xtables_error(PARAMETER_PROBLEM,
+				      "Only harware address length of 6 is supported currently.");
+	}
+	if (args->arp_opcode) {
+		if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
+				   &cs->arp.arp.arpop_mask, 10)) {
+			int i;
+
+			for (i = 0; i < NUMOPCODES; i++)
+				if (!strcasecmp(arp_opcodes[i],
+						args->arp_opcode))
+					break;
+			if (i == NUMOPCODES)
+				xtables_error(PARAMETER_PROBLEM,
+					      "Problem with specified opcode");
+			cs->arp.arp.arpop = htons(i+1);
+		}
+	}
+	if (args->arp_htype) {
+		if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
+				   &cs->arp.arp.arhrd_mask, 16)) {
+			if (strcasecmp(args->arp_htype, "Ethernet"))
+				xtables_error(PARAMETER_PROBLEM,
+					      "Problem with specified hardware type");
+			cs->arp.arp.arhrd = htons(1);
+		}
+	}
+	if (args->arp_ptype) {
+		if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
+				   &cs->arp.arp.arpro_mask, 0)) {
+			if (strcasecmp(args->arp_ptype, "ipv4"))
+				xtables_error(PARAMETER_PROBLEM,
+					      "Problem with specified protocol type");
+			cs->arp.arp.arpro = htons(0x800);
+		}
+	}
+}
+
 static void nft_arp_init_cs(struct iptables_command_state *cs)
 {
 	cs->arp.arp.arhln = 6;
@@ -565,7 +713,7 @@  struct nft_family_ops nft_family_ops_arp = {
 	.print_rule		= nft_arp_print_rule,
 	.save_rule		= nft_arp_save_rule,
 	.save_chain		= nft_arp_save_chain,
-	.post_parse		= NULL,
+	.post_parse		= nft_arp_post_parse,
 	.rule_to_cs		= nft_rule_to_iptables_command_state,
 	.init_cs		= nft_arp_init_cs,
 	.clear_cs		= nft_clear_iptables_command_state,
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index cb1c3fffe63b4..339c46e7f5b06 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -218,6 +218,9 @@  struct xtables_args {
 	const char	*shostnetworkmask, *dhostnetworkmask;
 	const char	*pcnt, *bcnt;
 	struct addr_mask s, d;
+	const char	*src_mac, *dst_mac;
+	const char	*arp_hlen, *arp_opcode;
+	const char	*arp_htype, *arp_ptype;
 	unsigned long long pcnt_cnt, bcnt_cnt;
 };
 
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 1075b6be74e98..de7c381788a37 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -108,54 +108,6 @@  struct xtables_globals arptables_globals = {
 	.print_help		= printhelp,
 };
 
-/***********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
-/***********************************************/
-
-static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
-{
-	char *p, *buffer;
-	int i;
-
-	if ( (p = strrchr(from, '/')) != NULL) {
-		*p = '\0';
-		i = strtol(p+1, &buffer, 10);
-		if (*buffer != '\0' || i < 0 || i > 255)
-			return -1;
-		*mask = (uint8_t)i;
-	} else
-		*mask = 255;
-	i = strtol(from, &buffer, 10);
-	if (*buffer != '\0' || i < 0 || i > 255)
-		return -1;
-	*to = (uint8_t)i;
-	return 0;
-}
-
-static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
-{
-	char *p, *buffer;
-	int i;
-
-	if ( (p = strrchr(from, '/')) != NULL) {
-		*p = '\0';
-		i = strtol(p+1, &buffer, base);
-		if (*buffer != '\0' || i < 0 || i > 65535)
-			return -1;
-		*mask = htons((uint16_t)i);
-	} else
-		*mask = 65535;
-	i = strtol(from, &buffer, base);
-	if (*buffer != '\0' || i < 0 || i > 65535)
-		return -1;
-	*to = htons((uint16_t)i);
-	return 0;
-}
-
-/*********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
-/*********************************************/
-
 static void
 exit_tryhelp(int status)
 {
@@ -566,132 +518,97 @@  int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			break;
 		case 's':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_SOURCE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_SOURCE, &args.invflags,
 				   invert);
 			args.shostnetworkmask = argv[optind-1];
 			break;
 
 		case 'd':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_DESTINATION, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_DESTINATION, &args.invflags,
 				   invert);
 			args.dhostnetworkmask = argv[optind-1];
 			break;
 
 		case 2:/* src-mac */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_S_MAC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_S_MAC, &args.invflags,
 				   invert);
-			if (xtables_parse_mac_and_mask(argv[optind - 1],
-			    cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
-				xtables_error(PARAMETER_PROBLEM, "Problem with specified "
-						"source mac");
+			args.src_mac = argv[optind - 1];
 			break;
 
 		case 3:/* dst-mac */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_D_MAC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_D_MAC, &args.invflags,
 				   invert);
-
-			if (xtables_parse_mac_and_mask(argv[optind - 1],
-			    cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
-				xtables_error(PARAMETER_PROBLEM, "Problem with specified "
-						"destination mac");
+			args.dst_mac = argv[optind - 1];
 			break;
 
 		case 'l':/* hardware length */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_H_LENGTH, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_H_LENGTH, &args.invflags,
 				   invert);
-			getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln,
-					   &cs.arp.arp.arhln_mask);
-
-			if (cs.arp.arp.arhln != 6) {
-				xtables_error(PARAMETER_PROBLEM,
-					      "Only harware address length of"
-					      " 6 is supported currently.");
-			}
-
+			args.arp_hlen = argv[optind - 1];
 			break;
 
 		case 8: /* was never supported, not even in arptables-legacy */
 			xtables_error(PARAMETER_PROBLEM, "not supported");
 		case 4:/* opcode */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_OPCODE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_OPCODE, &args.invflags,
 				   invert);
-			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop,
-					   &cs.arp.arp.arpop_mask, 10)) {
-				int i;
-
-				for (i = 0; i < NUMOPCODES; i++)
-					if (!strcasecmp(arp_opcodes[i], optarg))
-						break;
-				if (i == NUMOPCODES)
-					xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
-				cs.arp.arp.arpop = htons(i+1);
-			}
+			args.arp_opcode = argv[optind - 1];
 			break;
 
 		case 5:/* h-type */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_H_TYPE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_H_TYPE, &args.invflags,
 				   invert);
-			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd,
-					   &cs.arp.arp.arhrd_mask, 16)) {
-				if (strcasecmp(argv[optind-1], "Ethernet"))
-					xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
-				cs.arp.arp.arhrd = htons(1);
-			}
+			args.arp_htype = argv[optind - 1];
 			break;
 
 		case 6:/* proto-type */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_P_TYPE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_P_TYPE, &args.invflags,
 				   invert);
-			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro,
-					   &cs.arp.arp.arpro_mask, 0)) {
-				if (strcasecmp(argv[optind-1], "ipv4"))
-					xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
-				cs.arp.arp.arpro = htons(0x800);
-			}
+			args.arp_ptype = argv[optind - 1];
 			break;
 
 		case 'j':
-			set_option(&cs.options, OPT_JUMP, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_JUMP, &args.invflags,
 				   invert);
 			command_jump(&cs, optarg);
 			break;
 
 		case 'i':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_VIANAMEIN, &args.invflags,
 				   invert);
 			xtables_parse_interface(argv[optind-1],
-						cs.arp.arp.iniface,
-						cs.arp.arp.iniface_mask);
+						args.iniface,
+						args.iniface_mask);
 			break;
 
 		case 'o':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags,
 				   invert);
 			xtables_parse_interface(argv[optind-1],
-						cs.arp.arp.outiface,
-						cs.arp.arp.outiface_mask);
+						args.outiface,
+						args.outiface_mask);
 			break;
 
 		case 'v':
 			if (!p.verbose)
 				set_option(&cs.options, OPT_VERBOSE,
-					   &cs.arp.arp.invflags, invert);
+					   &args.invflags, invert);
 			p.verbose++;
 			break;
 
 		case 'm': /* ignored by arptables-legacy */
 			break;
 		case 'n':
-			set_option(&cs.options, OPT_NUMERIC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_NUMERIC, &args.invflags,
 				   invert);
 			break;
 
@@ -715,7 +632,7 @@  int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			exit(0);
 
 		case '0':
-			set_option(&cs.options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_LINENUMBERS, &args.invflags,
 				   invert);
 			break;
 
@@ -725,7 +642,7 @@  int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 'c':
 
-			set_option(&cs.options, OPT_COUNTERS, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_COUNTERS, &args.invflags,
 				   invert);
 			args.pcnt = optarg;
 			if (xs_has_arg(argc, argv))
@@ -781,25 +698,7 @@  int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 		xtables_error(PARAMETER_PROBLEM,
 			      "nothing appropriate following !");
 
-	if (p.command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
-		if (!(cs.options & OPT_DESTINATION))
-			args.dhostnetworkmask = "0.0.0.0/0";
-		if (!(cs.options & OPT_SOURCE))
-			args.shostnetworkmask = "0.0.0.0/0";
-	}
-
-	if (args.shostnetworkmask)
-		xtables_ipparse_multiple(args.shostnetworkmask, &args.s.addr.v4,
-					 &args.s.mask.v4, &args.s.naddrs);
-
-	if (args.dhostnetworkmask)
-		xtables_ipparse_multiple(args.dhostnetworkmask, &args.d.addr.v4,
-					 &args.d.mask.v4, &args.d.naddrs);
-
-	if ((args.s.naddrs > 1 || args.d.naddrs > 1) &&
-	    (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
-		xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
-				" source or destination IP addresses");
+	h->ops->post_parse(p.command, &cs, &args);
 
 	if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1))
 		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "