From 56aad1bb486675ff9aba31418708cc179eea0381 Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Sat, 20 Mar 2004 15:28:55 +0000
Subject: [PATCH] Applied Martin Kihlgren's IdentityGenerosity patch,
 simplified and renamed to StrictSource.

---
 src/graph.c      | 21 ++--------------
 src/net.h        |  1 +
 src/net_packet.c | 63 ++++++++++++++++++++++++++++++++----------------
 src/net_setup.c  |  2 ++
 src/node.c       | 22 +++++++++++++++++
 src/node.h       |  1 +
 6 files changed, 70 insertions(+), 40 deletions(-)

diff --git a/src/graph.c b/src/graph.c
index 3ed1d721..3870c709 100644
--- a/src/graph.c
+++ b/src/graph.c
@@ -219,25 +219,8 @@ void sssp_bfs(void)
 				e->to->via = indirect ? n->via : e->to;
 				e->to->options = e->options;
 
-				if(sockaddrcmp(&e->to->address, &e->address)) {
-					node = avl_unlink(node_udp_tree, e->to);
-					sockaddrfree(&e->to->address);
-					sockaddrcpy(&e->to->address, &e->address);
-
-					if(e->to->hostname)
-						free(e->to->hostname);
-
-					e->to->hostname = sockaddr2hostname(&e->to->address);
-					avl_insert_node(node_udp_tree, node);
-
-					if(e->to->options & OPTION_PMTU_DISCOVERY) {
-						e->to->mtuprobes = 0;
-						e->to->minmtu = 0;
-						e->to->maxmtu = MTU;
-						if(e->to->status.validkey)
-							send_mtu_probe(e->to);
-					}
-				}
+				if(sockaddrcmp(&e->to->address, &e->address))
+					update_node_address(e->to, &e->address);
 
 				node = avl_alloc_node();
 				node->data = e->to;
diff --git a/src/net.h b/src/net.h
index 5b145538..90463eb2 100644
--- a/src/net.h
+++ b/src/net.h
@@ -122,6 +122,7 @@ extern listen_socket_t listen_socket[MAXSOCKETS];
 extern int listen_sockets;
 extern int keyexpires;
 extern int keylifetime;
+extern bool strictsource;
 extern bool do_prune;
 extern bool do_purge;
 extern char *myport;
diff --git a/src/net_packet.c b/src/net_packet.c
index 255453e9..ae5a8402 100644
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -54,6 +54,7 @@
 
 int keylifetime = 0;
 int keyexpires = 0;
+bool strictsource = true;
 EVP_CIPHER_CTX packet_ctx;
 static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
 
@@ -167,6 +168,25 @@ static void receive_packet(node_t *n, vpn_packet_t *packet)
 	route(n, packet);
 }
 
+static bool authenticate_udppacket(node_t *n, vpn_packet_t *inpkt) {
+	char hmac[EVP_MAX_MD_SIZE];
+
+	if(inpkt->len < sizeof(inpkt->seqno) + (myself->digest ? myself->maclength : 0))
+		return false;
+
+	/* Check the message authentication code */
+
+	if(myself->digest && myself->maclength) {
+		HMAC(myself->digest, myself->key, myself->keylength,
+			 (char *) &inpkt->seqno, inpkt->len - myself->maclength, hmac, NULL);
+
+		if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len - myself->maclength, myself->maclength))
+			return false;
+	}
+
+	return true;
+}
+
 static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 {
 	vpn_packet_t pkt1, pkt2;
@@ -174,32 +194,17 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 	int nextpkt = 0;
 	vpn_packet_t *outpkt = pkt[0];
 	int outlen, outpad;
-	char hmac[EVP_MAX_MD_SIZE];
 	int i;
 
 	cp();
 
-	/* Check packet length */
-
-	if(inpkt->len < sizeof(inpkt->seqno) + myself->maclength) {
-		ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
-					n->name, n->hostname);
+	if(!authenticate_udppacket(n, inpkt)) {
+		ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
+					   n->name, n->hostname);
 		return;
 	}
 
-	/* Check the message authentication code */
-
-	if(myself->digest && myself->maclength) {
-		inpkt->len -= myself->maclength;
-		HMAC(myself->digest, myself->key, myself->keylength,
-			 (char *) &inpkt->seqno, inpkt->len, hmac, NULL);
-
-		if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, myself->maclength)) {
-			ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
-					   n->name, n->hostname);
-			return;
-		}
-	}
+	inpkt->len -= myself->digest ? myself->maclength : 0;
 
 	/* Decrypt the packet */
 
@@ -483,6 +488,7 @@ void handle_incoming_vpn_data(int sock)
 	sockaddr_t from;
 	socklen_t fromlen = sizeof(from);
 	node_t *n;
+	static time_t lasttime = 0;
 
 	cp();
 
@@ -497,10 +503,25 @@ void handle_incoming_vpn_data(int sock)
 
 	n = lookup_node_udp(&from);
 
+	if(!n && !strictsource && myself->digest && myself->maclength && lasttime != now) {
+		avl_node_t *node;
+
+		lasttime = now;
+
+		for(node = node_tree->head; node; node = node->next) {
+			n = node->data;
+
+			if(authenticate_udppacket(n, &pkt)) {
+				update_node_address(n, &from);
+				logger(LOG_DEBUG, _("Updated address of node %s to %s"), n->name, n->hostname);
+				break;
+			}
+		}
+	}
+
 	if(!n) {
 		hostname = sockaddr2hostname(&from);
-		logger(LOG_WARNING, _("Received UDP packet from unknown source %s"),
-			   hostname);
+		logger(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname);
 		free(hostname);
 		return;
 	}
diff --git a/src/net_setup.c b/src/net_setup.c
index aa2fbfbe..502e7b20 100644
--- a/src/net_setup.c
+++ b/src/net_setup.c
@@ -343,6 +343,8 @@ bool setup_myself(void)
 
 	get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);
 
+	get_config_bool(lookup_config(config_tree, "StrictSource"), &strictsource);
+
 	/* Generate packet encryption key */
 
 	if(get_config_string
diff --git a/src/node.c b/src/node.c
index 35199161..79320e71 100644
--- a/src/node.c
+++ b/src/node.c
@@ -150,6 +150,28 @@ void node_del(node_t *n)
 	avl_delete(node_udp_tree, n);
 }
 
+void update_node_address(node_t *n, const sockaddr_t address) {
+	avl_node_t *node;
+
+	node = avl_unlink(node_udp_tree, n);
+	sockaddrfree(&n->address);
+	sockaddrcpy(&n->address, &address);
+
+	if(n->hostname)
+		free(n->hostname);
+
+	n->hostname = sockaddr2hostname(&n->address);
+	avl_insert_node(node_udp_tree, node);
+
+	if(n->options & OPTION_PMTU_DISCOVERY) {
+		n->mtuprobes = 0;
+		n->minmtu = 0;
+		n->maxmtu = MTU;
+		if(n->status.validkey)
+			send_mtu_probe(n);
+	}
+}
+
 node_t *lookup_node(char *name)
 {
 	node_t n = {0};
diff --git a/src/node.h b/src/node.h
index dd9c7a12..6dc7338b 100644
--- a/src/node.h
+++ b/src/node.h
@@ -90,6 +90,7 @@ extern node_t *new_node(void) __attribute__ ((__malloc__));
 extern void free_node(node_t *);
 extern void node_add(node_t *);
 extern void node_del(node_t *);
+extern void update_node_udpaddress(node_t *, const sockaddr_t *);
 extern node_t *lookup_node(char *);
 extern node_t *lookup_node_udp(const sockaddr_t *);
 extern void dump_nodes(void);