From 835580878349b322052f977fc54016493252592b Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Fri, 3 Jan 2020 21:07:03 +0100
Subject: [PATCH 4/4] dump all connection parameters on management interface in
 key/value format

---
 src/openvpn/init.c   | 149 +++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/manage.c |   8 +++
 src/openvpn/manage.h |   3 +
 3 files changed, 160 insertions(+)

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index b37f5fa5..5654aa69 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1497,6 +1497,152 @@ do_init_route_ipv6_list(const struct options *options,
     }
 }
 
+#ifdef ENABLE_MANAGEMENT
+static void dump_conn_params(struct context *c, struct management *man)
+{
+        struct gc_arena gc = gc_new();
+        const char *out = NULL;
+	struct buffer b = alloc_buf_gc(8 * 1024, &gc);
+	struct tuntap *tt = c->c1.tuntap;
+	struct route_list *rl = c->c1.route_list;
+	struct route_ipv6_list *rl6 = c->c1.route_ipv6_list;
+        struct route_ipv4 *r;
+        struct route_ipv6 *r6;
+	struct env_item *ei;
+
+	buf_printf(&b, ">STATE:0,CONN_PARAMS,");
+
+	if (tt && tt->local) {
+		buf_printf(&b, "local4-%s|",
+			   print_in_addr_t(tt->local, IA_EMPTY_IF_UNDEF, &gc));
+        }
+
+	if (tt && tt->remote_netmask) {
+		if (tt->type == DEV_TYPE_TAP
+		    || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) {
+			buf_printf(&b, "netmask4-%s|",
+				   print_in_addr_t(tt->remote_netmask, IA_EMPTY_IF_UNDEF, &gc));
+
+			if (rl &&
+			    (rl->spec.flags & RTSA_REMOTE_ENDPOINT)) {
+				buf_printf(&b, "gateway4-%s|",
+					   print_in_addr_t(rl->spec.remote_endpoint,
+							   IA_EMPTY_IF_UNDEF, &gc));
+			}
+		} else
+			buf_printf(&b, "peer4-%s|",
+				   print_in_addr_t(tt->remote_netmask, IA_EMPTY_IF_UNDEF, &gc));
+        }
+
+	if (tt && rl) {
+	        for (r = rl->routes; r; r = r->next) {
+			buf_printf(&b, "route4-%s-%u-%s|",
+				   print_in_addr_t(r->network, IA_EMPTY_IF_UNDEF, &gc),
+				   netmask_to_netbits2(r->netmask),
+				   print_in_addr_t(r->gateway, IA_EMPTY_IF_UNDEF, &gc));
+		}
+	}
+
+	if (tt && !IN6_IS_ADDR_UNSPECIFIED(&tt->local_ipv6)) {
+		buf_printf(&b, "local6-%s|",
+			   print_in6_addr(tt->local_ipv6, IA_EMPTY_IF_UNDEF, &gc));
+	}
+
+	if (tt && !IN6_IS_ADDR_UNSPECIFIED(&tt->remote_ipv6)) {
+		buf_printf(&b, "peer6-%s|",
+			   print_in6_addr(tt->remote_ipv6, IA_EMPTY_IF_UNDEF, &gc));
+        }
+
+	if (tt && tt->netbits_ipv6 && tt->netbits_ipv6 != 128) {
+		buf_printf(&b, "onlink6-%s-%u|",
+			   print_in6_addr(tt->local_ipv6, IA_EMPTY_IF_UNDEF, &gc),
+			   tt->netbits_ipv6);
+        }
+
+	if (tt && rl6) {
+	        for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) {
+			const struct in6_addr *nh;
+
+			if (!IN6_IS_ADDR_UNSPECIFIED(&tt->remote_ipv6))
+				nh = &tt->remote_ipv6;
+			else
+				nh = &r6->gateway;
+
+			buf_printf(&b, "route6-%s-%u-%s|",
+				   print_in6_addr(r6->network, 0, &gc),
+				   r6->netbits,
+				   print_in6_addr(*nh, IA_EMPTY_IF_UNDEF, &gc));
+		}
+	}
+
+	ei = NULL;
+	if (c->c2.es)
+		ei = c->c2.es->list;
+
+	while (ei) {
+		struct in_addr dns4;
+		struct in6_addr dns6;
+		const char *p;
+		char buf[64];
+		int ret;
+
+		ret = snprintf(buf, sizeof (buf), "foreign_option_");
+
+		p = ei->string;
+		ei = ei->next;
+
+		if (strncmp(p, buf, ret))
+			continue;
+		p += ret;
+
+		while (*p && *p != '=')
+			p++;
+
+		if (!*p)
+			continue;
+		p++;
+
+		if (strncmp(p, "dhcp-option ", 12))
+			continue;
+
+		p += 12;
+		while (*p && *p == ' ')
+			p++;
+
+		if (!strncmp(p, "DNS ", 4))
+			p += 4;
+		else if (!strncmp(p, "DNS6 ", 5))
+			p += 5;
+		else
+			continue;
+
+		while (*p && *p == ' ')
+			p++;
+
+		if (inet_pton(AF_INET, p, &dns4) == 1) {
+			buf_printf(&b, "dns4-%s|",
+				   print_in_addr_t(dns4.s_addr, IA_EMPTY_IF_UNDEF |
+						   IA_NET_ORDER, &gc));
+			continue;
+		}
+
+		if (inet_pton(AF_INET6, p, &dns6) == 1) {
+			buf_printf(&b, "dns6-%s|",
+				   print_in6_addr(dns6, IA_EMPTY_IF_UNDEF, &gc));
+			continue;
+		}
+	}
+
+	buf_printf(&b, "mtu-%u\r\n",
+		   TUN_MTU_SIZE (&c->c2.frame));
+
+	out = BSTR(&b);
+	msg(D_MANAGEMENT, "MANAGEMENT: %s", out);
+	management_output_raw(man, out);
+	gc_free(&gc);
+}
+
+#endif
 
 /*
  * Called after all initialization has been completed.
@@ -1603,6 +1749,9 @@ initialization_sequence_completed(struct context *c, const unsigned int flags)
             tun_local = &c->c1.tuntap->local;
             tun_local6 = &c->c1.tuntap->local_ipv6;
         }
+
+	dump_conn_params(c, management);
+
         management_set_state(management,
                              OPENVPN_STATE_CONNECTED,
                              detail,
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index 805b0538..25dac6ef 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -171,6 +171,9 @@ man_state_name(const int state)
         case OPENVPN_STATE_WILL_CONNECT:
             return "WILL_CONNECT";
 
+        case OPENVPN_STATE_CONN_PARAMS:
+            return "CONN_PARAMS";
+
         default:
             return "?";
     }
@@ -2725,6 +2728,11 @@ management_set_state(struct management *man,
     }
 }
 
+void management_output_raw(struct management *man, const char *str)
+{
+	man_output_list_push(man, str);
+}
+
 static bool
 env_filter_match(const char *env_str, const int env_filter_level)
 {
diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h
index 3231e26b..9693a1d1 100644
--- a/src/openvpn/manage.h
+++ b/src/openvpn/manage.h
@@ -505,9 +505,12 @@ management_enable_def_auth(const struct management *man)
 #define OPENVPN_STATE_RESOLVE       10 /* DNS lookup */
 #define OPENVPN_STATE_TCP_CONNECT   11 /* Connecting to TCP server */
 #define OPENVPN_STATE_WILL_CONNECT   12 /* call after choosing remote */
+#define OPENVPN_STATE_CONN_PARAMS   13  /* dump all conn params before state connected */
 
 #define OPENVPN_STATE_CLIENT_BASE   7  /* Base index of client-only states */
 
+void management_output_raw(struct management *man, const char *str);
+
 void management_set_state(struct management *man,
                           const int state,
                           const char *detail,
-- 
2.17.1

