[Openvpn-devel,v2,1/7] implement platform generic networking API

Message ID 20181011184200.22175-2-a@unstable.cc
State Superseded
Headers show
Series introduce networking API and add netlink support for Linux | expand

Commit Message

Antonio Quartulli Oct. 11, 2018, 7:41 a.m. UTC
tun.c and route.c contain all the code used by openvpn
to manage the tun interface and the routing table on all
the supported platforms.

Across the years, this resulted in a longer functions
and series of ifdefs.

This patch introduces a new "networking API" which aims at
creating a simple abstraction between the tun/route logic
and the platform dependent code.

The is API expected to be implemented outside of tun.c/route.c
by using platform specific functionalities.

Signed-off-by: Antonio Quartulli <a@unstable.cc>
---
 src/openvpn/Makefile.am  |   1 +
 src/openvpn/networking.h | 278 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 279 insertions(+)
 create mode 100644 src/openvpn/networking.h

Comments

Arne Schwabe Nov. 26, 2018, 1:55 a.m. UTC | #1
Am 11.10.18 um 20:41 schrieb Antonio Quartulli:
> tun.c and route.c contain all the code used by openvpn
> to manage the tun interface and the routing table on all
> the supported platforms.
> 
> Across the years, this resulted in a longer functions
> and series of ifdefs.
> 
> This patch introduces a new "networking API" which aims at
> creating a simple abstraction between the tun/route logic
> and the platform dependent code.
> 
> The is API expected to be implemented outside of tun.c/route.c
> by using platform specific functionalities.

If I understand it right, the goal is to create a platform independent
API, Android needs either still hacks in the non platform specific code
or the API needs to communicate also

- route/adding addr before interface up
- type of route to add (android wants to ignores the host route to VPN
server and wants to isntall a 0.0.0.0/0 instead of two /1 even with def1
in place, the last one to workaround buggy Samsung code that special
cases 0.0.0.0/0 but sadly still needed.

Should we try to design the API right from the start to allow also for
these specifics?

Arne
Antonio Quartulli Nov. 26, 2018, 1:53 p.m. UTC | #2
Hi,

On 26/11/2018 22:55, Arne Schwabe wrote:
> Am 11.10.18 um 20:41 schrieb Antonio Quartulli:
>> tun.c and route.c contain all the code used by openvpn
>> to manage the tun interface and the routing table on all
>> the supported platforms.
>>
>> Across the years, this resulted in a longer functions
>> and series of ifdefs.
>>
>> This patch introduces a new "networking API" which aims at
>> creating a simple abstraction between the tun/route logic
>> and the platform dependent code.
>>
>> The is API expected to be implemented outside of tun.c/route.c
>> by using platform specific functionalities.
> 
> If I understand it right, the goal is to create a platform independent
> API, Android needs either still hacks in the non platform specific code
> or the API needs to communicate also
> 
> - route/adding addr before interface up
> - type of route to add (android wants to ignores the host route to VPN
> server and wants to isntall a 0.0.0.0/0 instead of two /1 even with def1
> in place, the last one to workaround buggy Samsung code that special
> cases 0.0.0.0/0 but sadly still needed.
> 
> Should we try to design the API right from the start to allow also for
> these specifics?
> 

This sounds like a problem that has to be addressed at a layer above
compared to what this networking API is doing.

With this I mean that the specific "Android case" you explained cannot
be addressed by changing the networking API (meant to be low level API
to configure/deconfigure th enetworking stack), but should be taken care
by the login in tun.c/route.c directly.

What yo are suggesting is a change to the logic passing the information
from the control plane to the platform dependent code.

This change to me seems independent from the technology used to
configure the interface (i.e. iproute/nettools/netlink/anything-else).

What you are after is probably an abstraction similar to the one we have
in OpenVPN 3, but that one is indeed implemented at an higher level
compared to what we are introducing with this patchset.

If you note, this is why my patches for OpenVPN 3 consists of two
components.

In my opinion, the logic change you are talking about is not required
because:
- this is already implemented in tun.c/route.c at the moment and won't
be changed for now
- this can be "improved" later once this networking API is in place,
because the code will have to deal with will already be much slimmer.

Attempting to work on both layers with one big change will just make
things more complicated imho, hence my proposal to go step by step.


Best Regards,

Patch

diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index 197e62ba..8afc4146 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -80,6 +80,7 @@  openvpn_SOURCES = \
 	mtu.c mtu.h \
 	mudp.c mudp.h \
 	multi.c multi.h \
+	networking.h \
 	ntlm.c ntlm.h \
 	occ.c occ.h \
 	openssl_compat.h \
diff --git a/src/openvpn/networking.h b/src/openvpn/networking.h
new file mode 100644
index 00000000..716e61a5
--- /dev/null
+++ b/src/openvpn/networking.h
@@ -0,0 +1,278 @@ 
+/*
+ *  Generic interface to platform specific networking code
+ *
+ *  Copyright (C) 2016-2018 Antonio Quartulli <a@unstable.cc>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef NETWORKING_H_
+#define NETWORKING_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+struct context;
+
+#ifdef ENABLE_SITNL
+#include "networking_sitnl.h"
+#elif ENABLE_IPROUTE
+#include "networking_ip.h"
+#else
+/* define mock types to ensure code builds on any platform */
+typedef void * openvpn_net_ctx_t;
+typedef void * openvpn_net_iface_t;
+
+static inline int
+net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
+{
+    return 0;
+}
+#endif
+
+#if defined(ENABLE_SITNL) || defined(ENABLE_IPROUTE)
+
+/**
+ * Initialize the platform specific context object
+ *
+ * @param c         openvpn generic context
+ * @param ctx       the implementation specific context to initialize
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx);
+
+/**
+ * Bring interface up or down.
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface to modify
+ * @param up        true if the interface has to be brought up, false otherwise
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_iface_up(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                 bool up);
+
+/**
+ * Set the MTU for an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface to modify
+ * @param mtru      the new MTU
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_iface_mtu_set(openvpn_net_ctx_t *ctx,
+                      const openvpn_net_iface_t *iface, uint32_t mtu);
+
+/**
+ * Add an IPv4 address to an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface where the address has to be added
+ * @param addr      the address to add
+ * @param prefixlen the prefix length of the network associated with the address
+ * @param broadcast the broadcast address to configure on the interface
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_addr_v4_add(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                    const in_addr_t *addr, int prefixlen,
+                    const in_addr_t *broadcast);
+
+/**
+ * Add an IPv6 address to an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface where the address has to be added
+ * @param addr      the address to add
+ * @param prefixlen the prefix length of the network associated with the address
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+
+int net_addr_v6_add(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                    const struct in6_addr *addr, int prefixlen);
+
+/**
+ * Remove an IPv4 from an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface to remove the address from
+ * @param prefixlen the prefix length of the network associated with the address
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_addr_v4_del(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                    const in_addr_t *addr, int prefixlen);
+
+/**
+ * Remove an IPv6 from an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface to remove the address from
+ * @param prefixlen the prefix length of the network associated with the address
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_addr_v6_del(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+                    const struct in6_addr *addr, int prefixlen);
+
+/**
+ * Add a point-to-point IPv4 address to an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface where the address has to be added
+ * @param local     the address to add
+ * @param remote    the associated p-t-p remote address
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx,
+                        const openvpn_net_iface_t *iface,
+                        const in_addr_t *local, const in_addr_t *remote);
+
+/**
+ * Remove a point-to-point IPv4 address from an interface
+ *
+ * @param ctx       the implementation specific context
+ * @param iface     the interface to remove the address from
+ * @param local     the address to remove
+ * @param remote    the associated p-t-p remote address
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx,
+                        const openvpn_net_iface_t *iface,
+                        const in_addr_t *local, const in_addr_t *remote);
+
+
+/**
+ * Add a route for an IPv4 address/network
+ *
+ * @param ctx       the implementation specific context
+ * @param dst       the destination of the route
+ * @param prefixlen the length of the prefix of the destination
+ * @param gw        the gateway for this route
+ * @param iface     the interface for this route (can be NULL)
+ * @param table     the table to add this route to (if 0, will be added to the
+ *                  main table)
+ * @param metric    the metric associated with the route
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
+                     int prefixlen, const in_addr_t *gw,
+                     const openvpn_net_iface_t *iface, uint32_t table,
+                     int metric);
+
+/**
+ * Add a route for an IPv6 address/network
+ *
+ * @param ctx       the implementation specific context
+ * @param dst       the destination of the route
+ * @param prefixlen the length of the prefix of the destination
+ * @param gw        the gateway for this route
+ * @param iface     the interface for this route (can be NULL)
+ * @param table     the table to add this route to (if 0, will be added to the
+ *                  main table)
+ * @param metric    the metric associated with the route
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
+                     int prefixlen, const struct in6_addr *gw,
+                     const openvpn_net_iface_t *iface,
+                     uint32_t table, int metric);
+
+/**
+ * Delete a route for an IPv4 address/network
+ *
+ * @param ctx       the implementation specific context
+ * @param dst       the destination of the route
+ * @param prefixlen the length of the prefix of the destination
+ * @param gw        the gateway for this route
+ * @param iface     the interface for this route (can be NULL)
+ * @param table     the table to add this route to (if 0, will be added to the
+ *                  main table)
+ * @param metric    the metric associated with the route
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
+                     int prefixlen, const in_addr_t *gw,
+                     const openvpn_net_iface_t *iface, uint32_t table,
+                     int metric);
+
+/**
+ * Delete a route for an IPv4 address/network
+ *
+ * @param ctx       the implementation specific context
+ * @param dst       the destination of the route
+ * @param prefixlen the length of the prefix of the destination
+ * @param gw        the gateway for this route
+ * @param iface     the interface for this route (can be NULL)
+ * @param table     the table to add this route to (if 0, will be added to the
+ *                  main table)
+ * @param metric    the metric associated with the route
+ *
+ * @return          0 on success, a negative error code otherwise
+ */
+int net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
+                     int prefixlen, const struct in6_addr *gw,
+                     const openvpn_net_iface_t *iface,
+                     uint32_t table, int metric);
+
+/**
+ * Retrieve the gateway and outgoing interface for the specified IPv4
+ * address/network
+ *
+ * @param ctx           the implementation specific context
+ * @param dst           The destination to lookup
+ * @param prefixlen     The length of the prefix of the destination
+ * @param best_gw       Location where the retrieved GW has to be stored
+ * @param best_iface    Location where the retrieved interface has to be stored
+ *
+ * @return              0 on success, a negative error code otherwise
+ */
+int net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
+                         int prefixlen, in_addr_t *best_gw,
+                         openvpn_net_iface_t *best_iface);
+
+/**
+ * Retrieve the gateway and outgoing interface for the specified IPv6
+ * address/network
+ *
+ * @param ctx           the implementation specific context
+ * @param dst           The destination to lookup
+ * @param prefixlen     The length of the prefix of the destination
+ * @param best_gw       Location where the retrieved GW has to be stored
+ * @param best_iface    Location where the retrieved interface has to be stored
+ *
+ * @return              0 on success, a negative error code otherwise
+ */
+int net_route_v6_best_gw(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
+                         int prefixlen, struct in6_addr *best_gw,
+                         openvpn_net_iface_t *best_iface);
+
+#endif /* ENABLE_SITNL || ENABLE_IPROUTE */
+
+#endif /* NETWORKING_H_ */