Description: Be more careful before using the fallback socket to send.
 The "fallback socket" mechanism is used when a packet may need to be
 routed and thus cannot be sent with LPF.  Using it to send to directly
 attached networks can cause traffic to be emitted with the wrong source,
 particularly when VPNs are in use.  Use it only when really necessary.
 .
 isc-dhcp (4.3.5-3+deb9u1) stretch-security; urgency=high
 .
   * Non-maintainer upload by the Security Team.
   * Plugs a socket descriptor leak in OMAPI (CVE-2017-3144) (Closes: #887413)
   * Corrected refcnt loss in option parsing (CVE-2018-5733) (Closes: #891785)
   * Correct buffer overrun in pretty_print_option (CVE-2018-5732)
     (Closes: #891786)
Author: Salvatore Bonaccorso <carnil@debian.org>
Bug-Debian: https://bugs.debian.org/887413
Bug-Debian: https://bugs.debian.org/891785
Bug-Debian: https://bugs.debian.org/891786

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: 2020-04-26

--- isc-dhcp-4.3.5.orig/client/dhclient.c
+++ isc-dhcp-4.3.5/client/dhclient.c
@@ -2444,6 +2444,73 @@ void state_panic (cpp)
 	go_daemon ();
 }
 
+/*
+ * Use of the "fallback" mechanism to send is supposed to be restricted
+ * only to cases in which the message need traverse a router to reach
+ * the DHCP server.  On systems with multiple network interfaces, and in
+ * particular VPN tunnels, too-enthusiastically using the default socket-
+ * based fallback mechanism can result into packets emitted onto the wrong
+ * network or, worse, onto the right network but with a source address
+ * which is, for that network, not valid (typically, this occurs if the
+ * system default route goes via a VPN, but the DHCP traffic is special-
+ * cased to the physical interface: the VPN local address will be emitted
+ * onto the physical link, which is wrong).  Some servers will process such
+ * messages anyway, and respond to the Client-IP within the message; but
+ * others drop them, NAK them, or, worse, blacklist the "malicious" client.
+ *
+ * Try to avoid this by checking if the server is on the local network, and,
+ * thus, routing cannot be required.
+ *
+ */
+int server_local (struct client_state *client)
+{
+	struct client_lease *active = client->active;
+	struct data_string data;
+	struct option_cache *oc;
+	struct iaddr caddr, saddr, cmask, cnet;
+	struct iaddrmatch cmatch;
+
+	if (!active) {
+		return 0;
+	}
+
+	/* Client and server addresses are easy. */
+
+	caddr = active -> address;
+	saddr = client -> destination;
+
+	/* The netmask, however, must be fished out of the lease's options.
+	   Paraphrased from script_write_params(). */
+	memset (&data, 0, sizeof data);
+	oc = lookup_option (&dhcp_universe, active -> options,
+			    DHO_SUBNET_MASK);
+	if (!oc) {
+		/* No interest in playing classful-network games */
+		return 0;
+	}
+	if (!evaluate_option_cache (&data, (struct packet *)0,
+				    (struct lease *)0, client,
+				    (struct option_state *)0,
+				    active -> options, &global_scope,
+				    oc, MDL)) {
+		/* Unparseable option? */
+		return 0;
+	}
+	if (data.len < 4) {
+		/* Play it safe */
+		return 0;
+	}
+	memcpy(cmask.iabuf, data.data, 4);
+	cmask.len = 4;
+	data_string_forget (&data, MDL);
+
+	cnet = subnet_number(caddr, cmask);
+	cmatch.addr = cnet;
+	cmatch.mask = cmask;
+
+	return addr_match(&saddr, &cmatch);
+}
+
 void send_request (cpp)
 	void *cpp;
 {
@@ -2603,7 +2670,7 @@ void send_request (cpp)
 	} else
 #endif
 	if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
-	    fallback_interface) {
+	    !server_local(client) && fallback_interface) {
 		result = send_packet(fallback_interface, NULL, &client->packet,
 				     client->packet_length, from, &destination,
 				     NULL);
@@ -2724,7 +2791,7 @@ void send_release (cpp)
 		}
 	} else
 #endif
-	if (fallback_interface) {
+	if (!server_local(client) && fallback_interface) {
 		result = send_packet(fallback_interface, NULL, &client->packet,
 				      client->packet_length, from, &destination,
 				      NULL);
