From b7792fa9d0d742f05175ff9c01d651ad76d525cc Mon Sep 17 00:00:00 2001
From: Ilia Pavlikhin <owl@ow1.in>
Date: Tue, 24 Sep 2019 15:34:12 +0000
Subject: [PATCH] Add Subnet checking to tinc cli

---
 src/conf.c         | 18 ++++++------------
 src/net.c          | 23 ++++++++++-------------
 src/subnet.h       |  1 +
 src/subnet_parse.c | 11 +++++++++++
 src/tincctl.c      | 14 ++++++++++++++
 5 files changed, 42 insertions(+), 25 deletions(-)

diff --git a/src/conf.c b/src/conf.c
index a33bdfea..4fcf82de 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -206,20 +206,14 @@ bool get_config_subnet(const config_t *cfg, subnet_t **result) {
 		return false;
 	}
 
-	/* Teach newbies what subnets are... */
-
-	if(((subnet.type == SUBNET_IPV4)
-	                && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(subnet.net.ipv4.address)))
-	                || ((subnet.type == SUBNET_IPV6)
-	                    && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(subnet.net.ipv6.address)))) {
-		logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
-		       cfg->variable, cfg->file, cfg->line);
-		return false;
+	if (subnetcheck(subnet)) {
+		*(*result = new_subnet()) = subnet;
+		return true;
 	}
 
-	*(*result = new_subnet()) = subnet;
-
-	return true;
+	logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
+	       cfg->variable, cfg->file, cfg->line);
+	return false;
 }
 
 /*
diff --git a/src/net.c b/src/net.c
index 22c9d372..8447d04c 100644
--- a/src/net.c
+++ b/src/net.c
@@ -404,21 +404,18 @@ int reload_configuration(void) {
 		while(cfg) {
 			subnet_t *subnet, *s2;
 
-			if(!get_config_subnet(cfg, &subnet)) {
-				cfg = lookup_config_next(config_tree, cfg);
-				continue;
-			}
+			if(get_config_subnet(cfg, &subnet)) {
+				if((s2 = lookup_subnet(myself, subnet))) {
+					if(s2->expires == 1) {
+						s2->expires = 0;
+					}
 
-			if((s2 = lookup_subnet(myself, subnet))) {
-				if(s2->expires == 1) {
-					s2->expires = 0;
+					free_subnet(subnet);
+				} else {
+					subnet_add(myself, subnet);
+					send_add_subnet(everyone, subnet);
+					subnet_update(myself, subnet, true);
 				}
-
-				free_subnet(subnet);
-			} else {
-				subnet_add(myself, subnet);
-				send_add_subnet(everyone, subnet);
-				subnet_update(myself, subnet, true);
 			}
 
 			cfg = lookup_config_next(config_tree, cfg);
diff --git a/src/subnet.h b/src/subnet.h
index cfdf2d0b..942853e9 100644
--- a/src/subnet.h
+++ b/src/subnet.h
@@ -78,6 +78,7 @@ extern void subnet_update(struct node_t *owner, subnet_t *subnet, bool up);
 extern int maskcmp(const void *a, const void *b, int masklen);
 extern void maskcpy(void *dest, const void *src, int masklen, int len);
 extern void mask(void *mask, int masklen, int len);
+extern bool subnetcheck(const subnet_t subnet);
 extern bool maskcheck(const void *mask, int masklen, int len);
 extern bool net2str(char *netstr, int len, const subnet_t *subnet);
 extern bool str2net(subnet_t *subnet, const char *netstr);
diff --git a/src/subnet_parse.c b/src/subnet_parse.c
index d5b84eb6..8616baa1 100644
--- a/src/subnet_parse.c
+++ b/src/subnet_parse.c
@@ -87,6 +87,17 @@ void maskcpy(void *va, const void *vb, int masklen, int len) {
 	}
 }
 
+bool subnetcheck(const subnet_t subnet) {
+	if(((subnet.type == SUBNET_IPV4)
+	                && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(subnet.net.ipv4.address)))
+	                || ((subnet.type == SUBNET_IPV6)
+	                    && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(subnet.net.ipv6.address)))) {
+		return false;
+	}
+
+	return true;
+}
+
 bool maskcheck(const void *va, int masklen, int len) {
 	int i;
 	const char *a = va;
diff --git a/src/tincctl.c b/src/tincctl.c
index 08f30189..0beebc21 100644
--- a/src/tincctl.c
+++ b/src/tincctl.c
@@ -40,6 +40,7 @@
 #include "tincctl.h"
 #include "top.h"
 #include "version.h"
+#include "subnet.h"
 
 #ifndef MSG_NOSIGNAL
 #define MSG_NOSIGNAL 0
@@ -1886,6 +1887,19 @@ static int cmd_config(int argc, char *argv[]) {
 		found = true;
 		variable = (char *)variables[i].name;
 
+		if (!strcasecmp(variable, "Subnet")) {
+			subnet_t s = {0};
+
+			if(!str2net(&s, value)) {
+				fprintf(stderr, "Malformed subnet definition %s\n", value);
+			}
+
+			if(!subnetcheck(s)) {
+				fprintf(stderr, "Network address and prefix length do not match: %s\n", value);
+				return 1;
+			}
+		}
+
 		/* Discourage use of obsolete variables. */
 
 		if(variables[i].type & VAR_OBSOLETE && action >= 0) {
-- 
2.39.5