From a9240ca9593e2bf207c0d080d4161f7ed5cdb9c4 Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Tue, 27 Jun 2017 13:06:17 +0200
Subject: [PATCH 1/2] export network paramsthrough management interface

---
 src/openvpn/init.c   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++----
 src/openvpn/manage.c | 32 +++++++++++++++++++---
 src/openvpn/manage.h | 14 ++++++++++
 3 files changed, 113 insertions(+), 8 deletions(-)

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index c6546e69..10112870 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1296,6 +1296,10 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
     {
       in_addr_t tun_local = 0;
       in_addr_t tun_remote = 0; /* FKS */
+      in_addr_t dns_ip[2] = { 0 };
+      int dns_count;
+      struct env_item *ei;
+
       const char *detail = "SUCCESS";
       if (c->c1.tuntap)
 	tun_local = c->c1.tuntap->local;
@@ -1307,11 +1311,62 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
       tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr);
       if (flags & ISC_ERRORS)
 	detail = "ERROR";
-      management_set_state (management,
-			    OPENVPN_STATE_CONNECTED,
-			    detail,
-			    tun_local,
-			    tun_remote);
+
+      dns_count = 0;
+      ei = NULL;
+      if (c->c2.es)
+	      ei = c->c2.es->list;
+
+      while (ei) {
+	      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))
+		      continue;
+
+	      p += 4;
+	      while (*p && *p == ' ')
+		      p++;
+
+	      if (inet_aton(p, &dns_ip[dns_count]) == 0)
+		      continue;
+
+	      dns_count++;
+	      if (dns_count == 2)
+		      break;
+      }
+      management_set_state_full (management,
+				 OPENVPN_STATE_CONNECTED,
+				 detail,
+				 tun_local,
+				 tun_remote,
+				 ntohl(dns_ip[0]),
+				 ntohl(dns_ip[1]),
+				 TUN_MTU_SIZE (&c->c2.frame));
       if (tun_local)
 	management_post_tunnel_open (management, tun_local);
     }
@@ -3451,6 +3506,16 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
   else if (c->mode == CM_CHILD_TCP)
     do_event_set_init (c, false);
 
+
+#ifdef ENABLE_MANAGEMENT
+  if (management)
+	  management_set_state (management,
+				OPENVPN_STATE_WILL_CONNECT,
+				c->options.ce.remote,
+				(in_addr_t)0,
+				(in_addr_t)0);
+#endif
+
   /* initialize HTTP or SOCKS proxy object at scope level 2 */
   init_proxy (c, 2);
 
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index d9471d19..49f8ed44 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -154,6 +154,8 @@ man_state_name (const int state)
       return "RESOLVE";
     case OPENVPN_STATE_TCP_CONNECT:
       return "TCP_CONNECT";
+    case OPENVPN_STATE_WILL_CONNECT:
+      return "WILL_CONNECT";
     default:
       return "?";
     }
@@ -2229,11 +2231,14 @@ management_clear_callback (struct management *man)
 }
 
 void
-management_set_state (struct management *man,
+management_set_state_full (struct management *man,
 		      const int state,
 		      const char *detail,
 		      const in_addr_t tun_local_ip,
-		      const in_addr_t tun_remote_ip)
+                      const in_addr_t tun_remote_ip,
+		      const in_addr_t tun_dns1_ip,
+                      const in_addr_t tun_dns2_ip,
+                      unsigned int tun_mtu)
 {
   if (man->persist.state && (!(man->settings.flags & MF_SERVER) || state < OPENVPN_STATE_CLIENT_BASE))
     {
@@ -2248,7 +2253,10 @@ management_set_state (struct management *man,
       e.string = detail;
       e.local_ip = tun_local_ip;
       e.remote_ip = tun_remote_ip;
-      
+      e.dns1_ip = tun_dns1_ip;
+      e.dns2_ip = tun_dns2_ip;
+      e.tun_mtu = tun_mtu;
+
       log_history_add (man->persist.state, &e);
 
       if (man->connection.state_realtime)
@@ -2267,6 +2275,18 @@ management_set_state (struct management *man,
     }
 }
 
+void
+management_set_state (struct management *man,
+		      const int state,
+		      const char *detail,
+		      const in_addr_t tun_local_ip,
+		      const in_addr_t tun_remote_ip)
+{
+	return management_set_state_full(man, state, detail,
+					 tun_local_ip, tun_remote_ip,
+					 0, 0, 0);
+}
+
 static bool
 env_filter_match (const char *env_str, const int env_filter_level)
 {
@@ -3219,6 +3239,12 @@ log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena
     buf_printf (&out, ",%s", print_in_addr_t (e->local_ip, IA_EMPTY_IF_UNDEF, gc));
   if (flags & LOG_PRINT_REMOTE_IP)
     buf_printf (&out, ",%s", print_in_addr_t (e->remote_ip, IA_EMPTY_IF_UNDEF, gc));
+  if (flags & LOG_PRINT_REMOTE_IP)
+    buf_printf (&out, ",%s", print_in_addr_t (e->dns1_ip, IA_EMPTY_IF_UNDEF, gc));
+  if (flags & LOG_PRINT_REMOTE_IP)
+    buf_printf (&out, ",%s", print_in_addr_t (e->dns2_ip, IA_EMPTY_IF_UNDEF, gc));
+  if (flags & LOG_PRINT_REMOTE_IP)
+    buf_printf (&out, ",%d", e->tun_mtu);
   if (flags & LOG_ECHO_TO_LOG)
     msg (D_MANAGEMENT, "MANAGEMENT: %s", BSTR (&out));
   if (flags & LOG_PRINT_CRLF)
diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h
index a08fe427..913b8871 100644
--- a/src/openvpn/manage.h
+++ b/src/openvpn/manage.h
@@ -89,6 +89,9 @@ struct log_entry
   const char *string;
   in_addr_t local_ip;
   in_addr_t remote_ip;
+  in_addr_t dns1_ip;
+  in_addr_t dns2_ip;
+  unsigned int tun_mtu;
   union log_entry_union u;
 };
 
@@ -472,12 +475,23 @@ management_enable_def_auth (const struct management *man)
 
 #define OPENVPN_STATE_CLIENT_BASE   7  /* Base index of client-only states */
 
+#define OPENVPN_STATE_WILL_CONNECT  12 /* call after choosing remote */
+
 void management_set_state (struct management *man,
 			   const int state,
 			   const char *detail,
 			   const in_addr_t tun_local_ip,
 			   const in_addr_t tun_remote_ip);
 
+void management_set_state_full (struct management *man,
+				const int state,
+				const char *detail,
+				const in_addr_t tun_local_ip,
+				const in_addr_t tun_remote_ip,
+				const in_addr_t tun_dns1_ip,
+				const in_addr_t tun_dns2_ip,
+				unsigned int tun_mtu);
+
 /*
  * The management object keeps track of OpenVPN --echo
  * parameters.
-- 
2.13.0

