From 18f9089e7430a85e05a19a754d832d4c59fedc0b Mon Sep 17 00:00:00 2001
From: Konstantin Kuzov <master.nosferatu@gmail.com>
Date: Fri, 31 Aug 2018 10:24:59 +0300
Subject: [PATCH 4/4] netifd: add dependency improvements

Choose randomly only one ip address from domain resolve during ppp tunnel bring up and use it. Case of constantly changing addresses of domain.
Ability to set interface through which this tunnel need to be routed or disable autorouting completely. Case of multiple interfaces/tunnels.
Clear stale route on tunnel down.
Disable disabling of availability of interface in netifd`s check dependencies where autoboot is enabled for now. This is done because currently tunnel can be stuck in non-available
state.

Signed-off-by: Konstantin Kuzov <master.nosferatu@gmail.com>
---
 .../files/etc/sysctl.d/20-helpers.conf        |  1 +
 .../patches/010-netifd-dep-improvements.patch | 94 +++++++++++++++++++
 package/network/services/ppp/files/ppp.sh     | 15 ++-
 3 files changed, 105 insertions(+), 5 deletions(-)
 create mode 100644 package/base-files/files/etc/sysctl.d/20-helpers.conf
 create mode 100644 package/network/config/netifd/patches/010-netifd-dep-improvements.patch

diff --git a/package/base-files/files/etc/sysctl.d/20-helpers.conf b/package/base-files/files/etc/sysctl.d/20-helpers.conf
new file mode 100644
index 0000000000..d1ae2cf578
--- /dev/null
+++ b/package/base-files/files/etc/sysctl.d/20-helpers.conf
@@ -0,0 +1 @@
+net.netfilter.nf_conntrack_helper=1
diff --git a/package/network/config/netifd/patches/010-netifd-dep-improvements.patch b/package/network/config/netifd/patches/010-netifd-dep-improvements.patch
new file mode 100644
index 0000000000..1765686665
--- /dev/null
+++ b/package/network/config/netifd/patches/010-netifd-dep-improvements.patch
@@ -0,0 +1,94 @@
+diff -urN a/interface-ip.c b/interface-ip.c
+--- a/interface-ip.c	2018-01-24 15:21:44.000000000 +0300
++++ b/interface-ip.c	2018-02-02 09:24:24.673182754 +0300
+@@ -282,6 +282,33 @@
+ 	return iface;
+ }
+ 
++struct interface *
++interface_ip_remove_target_route(union if_addr *addr, bool v6, struct interface *iface)
++{
++	struct device_route *route;
++	int addrsize = v6 ? sizeof(addr->in6) : sizeof(addr->in);
++
++	if (iface) {
++		vlist_for_each_element(&iface->host_routes, route, node) {
++			if (memcmp(&route->addr, addr, addrsize) == 0) {
++				vlist_delete(&iface->host_routes, &route->node);
++				return iface;
++			}
++		}
++	} else {
++		vlist_for_each_element(&interfaces, iface, node) {
++			vlist_for_each_element(&iface->host_routes, route, node) {
++				if (memcmp(&route->addr, addr, addrsize) == 0) {
++					vlist_delete(&iface->host_routes, &route->node);
++					return iface;
++			        }
++			}
++		}
++	}
++
++	return iface;
++}
++
+ static void
+ interface_set_route_info(struct interface *iface, struct device_route *route)
+ {
+diff -urN a/interface-ip.h b/interface-ip.h
+--- a/interface-ip.h	2018-01-24 15:21:44.000000000 +0300
++++ b/interface-ip.h	2018-02-02 09:24:24.673182754 +0300
+@@ -167,6 +167,7 @@
+ void interface_ip_update_metric(struct interface_ip_settings *ip, int metric);
+ 
+ struct interface *interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface);
++struct interface *interface_ip_remove_target_route(union if_addr *addr, bool v6, struct interface *iface);
+ 
+ struct device_prefix* interface_ip_add_device_prefix(struct interface *iface,
+ 		struct in6_addr *addr, uint8_t length, time_t valid_until, time_t preferred_until,
+diff -urN a/proto-shell.c b/proto-shell.c
+--- a/proto-shell.c	2018-01-24 15:21:44.000000000 +0300
++++ b/proto-shell.c	2018-02-02 12:13:15.243448308 +0300
+@@ -93,12 +93,17 @@
+ proto_shell_check_dependencies(struct proto_shell_state *state)
+ {
+ 	struct proto_shell_dependency *dep;
++	struct interface_proto_state *proto = &state->proto;
++	struct interface *iface = proto->iface;
+ 	bool available = true;
+ 
+ 	list_for_each_entry(dep, &state->deps, list) {
+ 		if (dep->dep.iface)
+ 			continue;
+ 
++		if (iface->autostart)
++			continue;
++
+ 		available = false;
+ 		break;
+ 	}
+@@ -146,8 +151,16 @@
+ proto_shell_clear_host_dep(struct proto_shell_state *state)
+ {
+ 	struct proto_shell_dependency *dep, *tmp;
++	struct interface *iface = NULL;
+ 
+ 	list_for_each_entry_safe(dep, tmp, &state->deps, list) {
++		if (dep->interface[0]) {
++			iface = vlist_find(&interfaces, dep->interface, iface, node);
++
++			if (iface && !dep->any)
++				iface = interface_ip_remove_target_route(&dep->host, dep->v6, iface);
++		}
++
+ 		interface_remove_user(&dep->dep);
+ 		list_del(&dep->list);
+ 		free(dep);
+@@ -221,6 +234,7 @@
+ 				snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error);
+ 				envp[j++] = error_buf;
+ 			}
++			proto_shell_clear_host_dep(state);
+ 			uloop_timeout_set(&state->teardown_timeout, 5000);
+ 			break;
+ 
diff --git a/package/network/services/ppp/files/ppp.sh b/package/network/services/ppp/files/ppp.sh
index 99d5e4939f..0d032c0d98 100755
--- a/package/network/services/ppp/files/ppp.sh
+++ b/package/network/services/ppp/files/ppp.sh
@@ -276,7 +276,8 @@ proto_pppoa_teardown() {
 proto_pptp_init_config() {
 	ppp_generic_init_config
 	proto_config_add_string "server"
-	proto_config_add_string "interface"
+	proto_config_add_boolean "route_disable"
+	proto_config_add_string "route_interface"
 	available=1
 	no_device=1
 	lasterror=1
@@ -286,11 +287,15 @@ proto_pptp_setup() {
 	local config="$1"
 	local iface="$2"
 
-	local ip serv_addr server interface
-	json_get_vars interface server
+	local ip serv_addr server route_interface route_disable
+	json_get_vars server route_interface route_disable
+
 	[ -n "$server" ] && {
-		for ip in $(resolveip -t 5 "$server"); do
-			( proto_add_host_dependency "$config" "$ip" $interface )
+		for ip in $(resolveip -14 -t 5 "$server"); do
+			if [ "$route_disable" != "1" ]; then
+				( proto_add_host_dependency "$config" "$ip" $route_interface )
+			fi
+			server=$ip
 			serv_addr=1
 		done
 	}
-- 
2.17.0

