Signed-off-by: Antonio Quartulli <a@unstable.cc>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <20220624083809.23487-2-a@unstable.cc>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg24512.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -143,6 +143,13 @@ AC_ARG_ENABLE( |
| 143 | 143 |
) |
| 144 | 144 |
|
| 145 | 145 |
AC_ARG_ENABLE( |
| 146 |
+ [dco], |
|
| 147 |
+ [AS_HELP_STRING([--enable-dco], [enable data channel offload support using ovpn-dco kernel module @<:@default=no@:>@])], |
|
| 148 |
+ , |
|
| 149 |
+ [enable_dco="no"] |
|
| 150 |
+) |
|
| 151 |
+ |
|
| 152 |
+AC_ARG_ENABLE( |
|
| 146 | 153 |
[iproute2], |
| 147 | 154 |
[AS_HELP_STRING([--enable-iproute2], [enable support for iproute2 @<:@default=no@:>@])], |
| 148 | 155 |
, |
| ... | ... |
@@ -760,6 +767,32 @@ PKG_CHECK_MODULES( |
| 760 | 760 |
[] |
| 761 | 761 |
) |
| 762 | 762 |
|
| 763 |
+ |
|
| 764 |
+if test "$enable_dco" = "yes"; then |
|
| 765 |
+dnl |
|
| 766 |
+dnl Include generic netlink library used to talk to ovpn-dco |
|
| 767 |
+dnl |
|
| 768 |
+ |
|
| 769 |
+ case "$host" in |
|
| 770 |
+ *-*-linux*) |
|
| 771 |
+ PKG_CHECK_MODULES([LIBNL_GENL], |
|
| 772 |
+ [libnl-genl-3.0 >= 3.4.0], |
|
| 773 |
+ [have_libnl="yes"], |
|
| 774 |
+ [AC_MSG_ERROR([libnl-genl-3.0 package not found or too old. Is the development package and pkg-config installed? Must be version 3.4.0 or newer])] |
|
| 775 |
+ ) |
|
| 776 |
+ |
|
| 777 |
+ CFLAGS="${CFLAGS} ${LIBNL_GENL_CFLAGS}"
|
|
| 778 |
+ LIBS="${LIBS} ${LIBNL_GENL_LIBS}"
|
|
| 779 |
+ |
|
| 780 |
+ AC_DEFINE(ENABLE_DCO, 1, [Enable shared data channel offload]) |
|
| 781 |
+ AC_MSG_NOTICE([Enabled ovpn-dco support for Linux]) |
|
| 782 |
+ ;; |
|
| 783 |
+ *) |
|
| 784 |
+ AC_MSG_NOTICE([Ignoring --enable-dco on non Linux platform]) |
|
| 785 |
+ ;; |
|
| 786 |
+ esac |
|
| 787 |
+fi |
|
| 788 |
+ |
|
| 763 | 789 |
if test "${with_crypto_library}" = "openssl"; then
|
| 764 | 790 |
AC_ARG_VAR([OPENSSL_CFLAGS], [C compiler flags for OpenSSL]) |
| 765 | 791 |
AC_ARG_VAR([OPENSSL_LIBS], [linker flags for OpenSSL]) |
| ... | ... |
@@ -1196,6 +1229,7 @@ fi |
| 1196 | 1196 |
AM_CONDITIONAL([HAVE_SITNL], [false]) |
| 1197 | 1197 |
|
| 1198 | 1198 |
if test "${enable_iproute2}" = "yes"; then
|
| 1199 |
+ test "${enable_dco}" = "yes" && AC_MSG_ERROR([iproute2 support cannot be enabled when using DCO])
|
|
| 1199 | 1200 |
test -z "${IPROUTE}" && AC_MSG_ERROR([ip utility is required but missing])
|
| 1200 | 1201 |
AC_DEFINE([ENABLE_IPROUTE], [1], [enable iproute2 support]) |
| 1201 | 1202 |
else if test "${have_sitnl}" = "yes"; then
|
| ... | ... |
@@ -1,3 +1,4 @@ |
| 1 | 1 |
E:doc/doxygen/doc_key_generation.h # @verbatim section gets mistreated, exclude it |
| 2 | 2 |
E:src/compat/compat-lz4.c # Preserve LZ4 upstream formatting |
| 3 | 3 |
E:src/compat/compat-lz4.h # Preserve LZ4 upstream formatting |
| 4 |
+E:src/openvpn/ovpn_dco_linux.h # Preserve ovpn-dco upstream formatting |
| ... | ... |
@@ -53,6 +53,8 @@ openvpn_SOURCES = \ |
| 53 | 53 |
crypto.c crypto.h crypto_backend.h \ |
| 54 | 54 |
crypto_openssl.c crypto_openssl.h \ |
| 55 | 55 |
crypto_mbedtls.c crypto_mbedtls.h \ |
| 56 |
+ dco.h dco_internal.h \ |
|
| 57 |
+ dco_linux.c dco_linux.h \ |
|
| 56 | 58 |
dhcp.c dhcp.h \ |
| 57 | 59 |
dns.c dns.h \ |
| 58 | 60 |
env_set.c env_set.h \ |
| ... | ... |
@@ -75,6 +77,7 @@ openvpn_SOURCES = \ |
| 75 | 75 |
mbuf.c mbuf.h \ |
| 76 | 76 |
memdbg.h \ |
| 77 | 77 |
misc.c misc.h \ |
| 78 |
+ ovpn_dco_linux.h \ |
|
| 78 | 79 |
platform.c platform.h \ |
| 79 | 80 |
console.c console.h console_builtin.c console_systemd.c \ |
| 80 | 81 |
mroute.c mroute.h \ |
| 81 | 82 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,165 @@ |
| 0 |
+/* |
|
| 1 |
+ * OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+ * over a single TCP/UDP port, with support for SSL/TLS-based |
|
| 3 |
+ * session authentication and key exchange, |
|
| 4 |
+ * packet encryption, packet authentication, and |
|
| 5 |
+ * packet compression. |
|
| 6 |
+ * |
|
| 7 |
+ * Copyright (C) 2021-2022 Arne Schwabe <arne@rfc2549.org> |
|
| 8 |
+ * Copyright (C) 2021-2022 Antonio Quartulli <a@unstable.cc> |
|
| 9 |
+ * Copyright (C) 2021-2022 OpenVPN Inc <sales@openvpn.net> |
|
| 10 |
+ * |
|
| 11 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 12 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 13 |
+ * as published by the Free Software Foundation. |
|
| 14 |
+ * |
|
| 15 |
+ * This program is distributed in the hope that it will be useful, |
|
| 16 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 17 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 18 |
+ * GNU General Public License for more details. |
|
| 19 |
+ * |
|
| 20 |
+ * You should have received a copy of the GNU General Public License |
|
| 21 |
+ * along with this program (see the file COPYING included with this |
|
| 22 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 23 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 24 |
+ */ |
|
| 25 |
+#ifndef DCO_H |
|
| 26 |
+#define DCO_H |
|
| 27 |
+ |
|
| 28 |
+#include "buffer.h" |
|
| 29 |
+#include "error.h" |
|
| 30 |
+#include "dco_internal.h" |
|
| 31 |
+#include "networking.h" |
|
| 32 |
+ |
|
| 33 |
+/* forward declarations (including other headers leads to nasty include |
|
| 34 |
+ * order problems) |
|
| 35 |
+ */ |
|
| 36 |
+struct event_set; |
|
| 37 |
+struct options; |
|
| 38 |
+struct tuntap; |
|
| 39 |
+ |
|
| 40 |
+#if defined(ENABLE_DCO) |
|
| 41 |
+ |
|
| 42 |
+/** |
|
| 43 |
+ * Check whether ovpn-dco is available on this platform (i.e. kernel support is |
|
| 44 |
+ * there) |
|
| 45 |
+ * |
|
| 46 |
+ * @param msglevel level to print messages to |
|
| 47 |
+ * @return true if ovpn-dco is available, false otherwise |
|
| 48 |
+ */ |
|
| 49 |
+bool dco_available(int msglevel); |
|
| 50 |
+ |
|
| 51 |
+/** |
|
| 52 |
+ * Check whether the options struct has any option that is not supported by |
|
| 53 |
+ * our current dco implementation. If so print a warning at warning level |
|
| 54 |
+ * for the first conflicting option found and return false. |
|
| 55 |
+ * |
|
| 56 |
+ * @param msglevel the msg level to use to print the warnings |
|
| 57 |
+ * @param o the options struct that hold the options |
|
| 58 |
+ * @return true if no conflict was detected, false otherwise |
|
| 59 |
+ */ |
|
| 60 |
+bool dco_check_option_conflict(int msglevel, const struct options *o); |
|
| 61 |
+ |
|
| 62 |
+/** |
|
| 63 |
+ * Initialize the DCO context |
|
| 64 |
+ * |
|
| 65 |
+ * @param mode the instance operating mode (P2P or multi-peer) |
|
| 66 |
+ * @param dco the context to initialize |
|
| 67 |
+ * @return true on success, false otherwise |
|
| 68 |
+ */ |
|
| 69 |
+bool ovpn_dco_init(int mode, dco_context_t *dco); |
|
| 70 |
+ |
|
| 71 |
+/** |
|
| 72 |
+ * Open/create a DCO interface |
|
| 73 |
+ * |
|
| 74 |
+ * @param tt the tuntap context |
|
| 75 |
+ * @param ctx the networking API context |
|
| 76 |
+ * @param dev the name of the interface to create |
|
| 77 |
+ * @return 0 on success or a negative error code otherwise |
|
| 78 |
+ */ |
|
| 79 |
+int open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev); |
|
| 80 |
+ |
|
| 81 |
+/** |
|
| 82 |
+ * Close/destroy a DCO interface |
|
| 83 |
+ * |
|
| 84 |
+ * @param tt the tuntap context |
|
| 85 |
+ * @param ctx the networking API context |
|
| 86 |
+ */ |
|
| 87 |
+void close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx); |
|
| 88 |
+ |
|
| 89 |
+/** |
|
| 90 |
+ * Read data from the DCO communication channel (i.e. a control packet) |
|
| 91 |
+ * |
|
| 92 |
+ * @param dco the DCO context |
|
| 93 |
+ * @return 0 on success or a negative error code otherwise |
|
| 94 |
+ */ |
|
| 95 |
+int dco_do_read(dco_context_t *dco); |
|
| 96 |
+ |
|
| 97 |
+/** |
|
| 98 |
+ * Write data to the DCO communication channel (control packet expected) |
|
| 99 |
+ * |
|
| 100 |
+ * @param dco the DCO context |
|
| 101 |
+ * @param peer_id the ID of the peer to send the data to |
|
| 102 |
+ * @param buf the buffer containing the data to send |
|
| 103 |
+ */ |
|
| 104 |
+int dco_do_write(dco_context_t *dco, int peer_id, struct buffer *buf); |
|
| 105 |
+ |
|
| 106 |
+/** |
|
| 107 |
+ * Install a DCO in the main event loop |
|
| 108 |
+ */ |
|
| 109 |
+void dco_event_set(dco_context_t *dco, struct event_set *es, void *arg); |
|
| 110 |
+ |
|
| 111 |
+#else /* if defined(ENABLE_DCO) */ |
|
| 112 |
+ |
|
| 113 |
+typedef void *dco_context_t; |
|
| 114 |
+ |
|
| 115 |
+static inline bool |
|
| 116 |
+dco_available(int msglevel) |
|
| 117 |
+{
|
|
| 118 |
+ return false; |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+static inline bool |
|
| 122 |
+dco_check_option_conflict(int msglevel, const struct options *o) |
|
| 123 |
+{
|
|
| 124 |
+ return false; |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+static inline bool |
|
| 128 |
+ovpn_dco_init(int mode, dco_context_t *dco) |
|
| 129 |
+{
|
|
| 130 |
+ return true; |
|
| 131 |
+} |
|
| 132 |
+ |
|
| 133 |
+static inline int |
|
| 134 |
+open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev) |
|
| 135 |
+{
|
|
| 136 |
+ return 0; |
|
| 137 |
+} |
|
| 138 |
+ |
|
| 139 |
+static inline void |
|
| 140 |
+close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx) |
|
| 141 |
+{
|
|
| 142 |
+} |
|
| 143 |
+ |
|
| 144 |
+static inline int |
|
| 145 |
+dco_do_read(dco_context_t *dco) |
|
| 146 |
+{
|
|
| 147 |
+ ASSERT(false); |
|
| 148 |
+ return 0; |
|
| 149 |
+} |
|
| 150 |
+ |
|
| 151 |
+static inline int |
|
| 152 |
+dco_do_write(dco_context_t *dco, int peer_id, struct buffer *buf) |
|
| 153 |
+{
|
|
| 154 |
+ ASSERT(false); |
|
| 155 |
+ return 0; |
|
| 156 |
+} |
|
| 157 |
+ |
|
| 158 |
+static inline void |
|
| 159 |
+dco_event_set(dco_context_t *dco, struct event_set *es, void *arg) |
|
| 160 |
+{
|
|
| 161 |
+} |
|
| 162 |
+ |
|
| 163 |
+#endif /* defined(ENABLE_DCO) */ |
|
| 164 |
+#endif /* ifndef DCO_H */ |
| 0 | 165 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,78 @@ |
| 0 |
+/* |
|
| 1 |
+ * OpenVPN -- An application to securely tunnel IP networks |
|
| 2 |
+ * over a single TCP/UDP port, with support for SSL/TLS-based |
|
| 3 |
+ * session authentication and key exchange, |
|
| 4 |
+ * packet encryption, packet authentication, and |
|
| 5 |
+ * packet compression. |
|
| 6 |
+ * |
|
| 7 |
+ * Copyright (C) 2022 Antonio Quartulli <a@unstable.cc> |
|
| 8 |
+ * Copyright (C) 2022 OpenVPN Inc <sales@openvpn.net> |
|
| 9 |
+ * |
|
| 10 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 11 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 12 |
+ * as published by the Free Software Foundation. |
|
| 13 |
+ * |
|
| 14 |
+ * This program is distributed in the hope that it will be useful, |
|
| 15 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 16 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 17 |
+ * GNU General Public License for more details. |
|
| 18 |
+ * |
|
| 19 |
+ * You should have received a copy of the GNU General Public License |
|
| 20 |
+ * along with this program (see the file COPYING included with this |
|
| 21 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 22 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 23 |
+ */ |
|
| 24 |
+#ifndef DCO_INTERNAL_H |
|
| 25 |
+#define DCO_INTERNAL_H |
|
| 26 |
+ |
|
| 27 |
+#if defined(ENABLE_DCO) |
|
| 28 |
+ |
|
| 29 |
+#include "dco_linux.h" |
|
| 30 |
+ |
|
| 31 |
+/** |
|
| 32 |
+ * This file contains the internal DCO API definition. |
|
| 33 |
+ * It is expected that this file is included only in dco.h. |
|
| 34 |
+ * The OpenVPN code should never directly include this file |
|
| 35 |
+ */ |
|
| 36 |
+ |
|
| 37 |
+static inline dco_cipher_t |
|
| 38 |
+dco_get_cipher(const char *cipher) |
|
| 39 |
+{
|
|
| 40 |
+ if (strcmp(cipher, "AES-256-GCM") == 0 || strcmp(cipher, "AES-128-GCM") == 0 |
|
| 41 |
+ || strcmp(cipher, "AES-192-GCM") == 0) |
|
| 42 |
+ {
|
|
| 43 |
+ return OVPN_CIPHER_ALG_AES_GCM; |
|
| 44 |
+ } |
|
| 45 |
+ else if (strcmp(cipher, "CHACHA20-POLY1305") == 0) |
|
| 46 |
+ {
|
|
| 47 |
+ return OVPN_CIPHER_ALG_CHACHA20_POLY1305; |
|
| 48 |
+ } |
|
| 49 |
+ else |
|
| 50 |
+ {
|
|
| 51 |
+ msg(M_FATAL, "DCO: provided unsupported cipher: %s", cipher); |
|
| 52 |
+ } |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+/** |
|
| 56 |
+ * The following are the DCO APIs used to control the driver. |
|
| 57 |
+ * They are implemented by dco_linux.c |
|
| 58 |
+ */ |
|
| 59 |
+ |
|
| 60 |
+int dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, |
|
| 61 |
+ struct sockaddr *localaddr, struct sockaddr *remoteaddr, |
|
| 62 |
+ struct in_addr *remote_in4, struct in6_addr *remote_in6); |
|
| 63 |
+ |
|
| 64 |
+int dco_del_peer(dco_context_t *dco, unsigned int peerid); |
|
| 65 |
+ |
|
| 66 |
+int dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, |
|
| 67 |
+ dco_key_slot_t slot, |
|
| 68 |
+ const uint8_t *encrypt_key, const uint8_t *encrypt_iv, |
|
| 69 |
+ const uint8_t *decrypt_key, const uint8_t *decrypt_iv, |
|
| 70 |
+ const char *ciphername); |
|
| 71 |
+ |
|
| 72 |
+int dco_del_key(dco_context_t *dco, unsigned int peerid, dco_key_slot_t slot); |
|
| 73 |
+ |
|
| 74 |
+int dco_swap_keys(dco_context_t *dco, unsigned int peerid); |
|
| 75 |
+ |
|
| 76 |
+#endif /* defined(ENABLE_DCO) */ |
|
| 77 |
+#endif /* ifndef DCO_INTERNAL_H */ |
| 0 | 78 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,934 @@ |
| 0 |
+/* |
|
| 1 |
+ * Interface to linux dco networking code |
|
| 2 |
+ * |
|
| 3 |
+ * Copyright (C) 2020-2022 Antonio Quartulli <a@unstable.cc> |
|
| 4 |
+ * Copyright (C) 2020-2022 Arne Schwabe <arne@rfc2549.org> |
|
| 5 |
+ * Copyright (C) 2020-2022 OpenVPN Inc <sales@openvpn.net> |
|
| 6 |
+ * |
|
| 7 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 8 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 9 |
+ * as published by the Free Software Foundation. |
|
| 10 |
+ * |
|
| 11 |
+ * This program is distributed in the hope that it will be useful, |
|
| 12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
+ * GNU General Public License for more details. |
|
| 15 |
+ * |
|
| 16 |
+ * You should have received a copy of the GNU General Public License |
|
| 17 |
+ * along with this program (see the file COPYING included with this |
|
| 18 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 19 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 20 |
+ */ |
|
| 21 |
+ |
|
| 22 |
+ |
|
| 23 |
+#ifdef HAVE_CONFIG_H |
|
| 24 |
+#include "config.h" |
|
| 25 |
+#elif defined(_MSC_VER) |
|
| 26 |
+#include "config-msvc.h" |
|
| 27 |
+#endif |
|
| 28 |
+ |
|
| 29 |
+#if defined(ENABLE_DCO) && defined(TARGET_LINUX) |
|
| 30 |
+ |
|
| 31 |
+#include "syshead.h" |
|
| 32 |
+ |
|
| 33 |
+#include "dco_linux.h" |
|
| 34 |
+#include "errlevel.h" |
|
| 35 |
+#include "buffer.h" |
|
| 36 |
+#include "networking.h" |
|
| 37 |
+#include "openvpn.h" |
|
| 38 |
+ |
|
| 39 |
+#include "socket.h" |
|
| 40 |
+#include "tun.h" |
|
| 41 |
+#include "ssl.h" |
|
| 42 |
+#include "fdmisc.h" |
|
| 43 |
+#include "ssl_verify.h" |
|
| 44 |
+ |
|
| 45 |
+#include "ovpn_dco_linux.h" |
|
| 46 |
+ |
|
| 47 |
+#include <netlink/socket.h> |
|
| 48 |
+#include <netlink/netlink.h> |
|
| 49 |
+#include <netlink/genl/genl.h> |
|
| 50 |
+#include <netlink/genl/family.h> |
|
| 51 |
+#include <netlink/genl/ctrl.h> |
|
| 52 |
+ |
|
| 53 |
+ |
|
| 54 |
+/* libnl < 3.5.0 does not set the NLA_F_NESTED on its own, therefore we |
|
| 55 |
+ * have to explicitly do it to prevent the kernel from failing upon |
|
| 56 |
+ * parsing of the message |
|
| 57 |
+ */ |
|
| 58 |
+#define nla_nest_start(_msg, _type) \ |
|
| 59 |
+ nla_nest_start(_msg, (_type) | NLA_F_NESTED) |
|
| 60 |
+ |
|
| 61 |
+static int ovpn_get_mcast_id(dco_context_t *dco); |
|
| 62 |
+ |
|
| 63 |
+void dco_check_key_ctx(const struct key_ctx_bi *key); |
|
| 64 |
+ |
|
| 65 |
+typedef int (*ovpn_nl_cb)(struct nl_msg *msg, void *arg); |
|
| 66 |
+ |
|
| 67 |
+/** |
|
| 68 |
+ * @brief resolves the netlink ID for ovpn-dco |
|
| 69 |
+ * |
|
| 70 |
+ * This function queries the kernel via a netlink socket |
|
| 71 |
+ * whether the ovpn-dco netlink namespace is available |
|
| 72 |
+ * |
|
| 73 |
+ * This function can be used to determine if the kernel |
|
| 74 |
+ * supports DCO offloading. |
|
| 75 |
+ * |
|
| 76 |
+ * @return ID on success, negative error code on error |
|
| 77 |
+ */ |
|
| 78 |
+static int |
|
| 79 |
+resolve_ovpn_netlink_id(int msglevel) |
|
| 80 |
+{
|
|
| 81 |
+ int ret; |
|
| 82 |
+ struct nl_sock *nl_sock = nl_socket_alloc(); |
|
| 83 |
+ |
|
| 84 |
+ ret = genl_connect(nl_sock); |
|
| 85 |
+ if (ret) |
|
| 86 |
+ {
|
|
| 87 |
+ msg(msglevel, "Cannot connect to generic netlink: %s", |
|
| 88 |
+ nl_geterror(ret)); |
|
| 89 |
+ goto err_sock; |
|
| 90 |
+ } |
|
| 91 |
+ set_cloexec(nl_socket_get_fd(nl_sock)); |
|
| 92 |
+ |
|
| 93 |
+ ret = genl_ctrl_resolve(nl_sock, OVPN_NL_NAME); |
|
| 94 |
+ if (ret < 0) |
|
| 95 |
+ {
|
|
| 96 |
+ msg(msglevel, "Cannot find ovpn_dco netlink component: %s", |
|
| 97 |
+ nl_geterror(ret)); |
|
| 98 |
+ } |
|
| 99 |
+ |
|
| 100 |
+err_sock: |
|
| 101 |
+ nl_socket_free(nl_sock); |
|
| 102 |
+ return ret; |
|
| 103 |
+} |
|
| 104 |
+ |
|
| 105 |
+static struct nl_msg * |
|
| 106 |
+ovpn_dco_nlmsg_create(dco_context_t *dco, enum ovpn_nl_commands cmd) |
|
| 107 |
+{
|
|
| 108 |
+ struct nl_msg *nl_msg = nlmsg_alloc(); |
|
| 109 |
+ if (!nl_msg) |
|
| 110 |
+ {
|
|
| 111 |
+ msg(M_ERR, "cannot allocate netlink message"); |
|
| 112 |
+ return NULL; |
|
| 113 |
+ } |
|
| 114 |
+ |
|
| 115 |
+ genlmsg_put(nl_msg, 0, 0, dco->ovpn_dco_id, 0, 0, cmd, 0); |
|
| 116 |
+ NLA_PUT_U32(nl_msg, OVPN_ATTR_IFINDEX, dco->ifindex); |
|
| 117 |
+ |
|
| 118 |
+ return nl_msg; |
|
| 119 |
+nla_put_failure: |
|
| 120 |
+ nlmsg_free(nl_msg); |
|
| 121 |
+ msg(M_INFO, "cannot put into netlink message"); |
|
| 122 |
+ return NULL; |
|
| 123 |
+} |
|
| 124 |
+ |
|
| 125 |
+static int |
|
| 126 |
+ovpn_nl_recvmsgs(dco_context_t *dco, const char *prefix) |
|
| 127 |
+{
|
|
| 128 |
+ int ret = nl_recvmsgs(dco->nl_sock, dco->nl_cb); |
|
| 129 |
+ |
|
| 130 |
+ switch (ret) |
|
| 131 |
+ {
|
|
| 132 |
+ case -NLE_INTR: |
|
| 133 |
+ msg(M_WARN, "%s: netlink received interrupt due to signal - ignoring", prefix); |
|
| 134 |
+ break; |
|
| 135 |
+ |
|
| 136 |
+ case -NLE_NOMEM: |
|
| 137 |
+ msg(M_ERR, "%s: netlink out of memory error", prefix); |
|
| 138 |
+ break; |
|
| 139 |
+ |
|
| 140 |
+ case -M_ERR: |
|
| 141 |
+ msg(M_WARN, "%s: netlink reports blocking read - aborting wait", prefix); |
|
| 142 |
+ break; |
|
| 143 |
+ |
|
| 144 |
+ case -NLE_NODEV: |
|
| 145 |
+ msg(M_ERR, "%s: netlink reports device not found:", prefix); |
|
| 146 |
+ break; |
|
| 147 |
+ |
|
| 148 |
+ case -NLE_OBJ_NOTFOUND: |
|
| 149 |
+ msg(M_INFO, "%s: netlink reports object not found, ovpn-dco unloaded?", prefix); |
|
| 150 |
+ break; |
|
| 151 |
+ |
|
| 152 |
+ default: |
|
| 153 |
+ if (ret) |
|
| 154 |
+ {
|
|
| 155 |
+ msg(M_NONFATAL|M_ERRNO, "%s: netlink reports error (%d): %s", prefix, ret, nl_geterror(-ret)); |
|
| 156 |
+ } |
|
| 157 |
+ break; |
|
| 158 |
+ } |
|
| 159 |
+ |
|
| 160 |
+ return ret; |
|
| 161 |
+} |
|
| 162 |
+ |
|
| 163 |
+/** |
|
| 164 |
+ * Send a prepared netlink message and registers cb as callback if non-null. |
|
| 165 |
+ * |
|
| 166 |
+ * The method will also free nl_msg |
|
| 167 |
+ * @param dco The dco context to use |
|
| 168 |
+ * @param nl_msg the message to use |
|
| 169 |
+ * @param cb An optional callback if the caller expects an answer |
|
| 170 |
+ * @param prefix A prefix to report in the error message to give the user context |
|
| 171 |
+ * @return status of sending the message |
|
| 172 |
+ */ |
|
| 173 |
+static int |
|
| 174 |
+ovpn_nl_msg_send(dco_context_t *dco, struct nl_msg *nl_msg, ovpn_nl_cb cb, |
|
| 175 |
+ const char *prefix) |
|
| 176 |
+{
|
|
| 177 |
+ dco->status = 1; |
|
| 178 |
+ |
|
| 179 |
+ nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, cb, dco); |
|
| 180 |
+ nl_send_auto(dco->nl_sock, nl_msg); |
|
| 181 |
+ |
|
| 182 |
+ while (dco->status == 1) |
|
| 183 |
+ {
|
|
| 184 |
+ ovpn_nl_recvmsgs(dco, prefix); |
|
| 185 |
+ } |
|
| 186 |
+ |
|
| 187 |
+ if (dco->status < 0) |
|
| 188 |
+ {
|
|
| 189 |
+ msg(M_INFO, "%s: failed to send netlink message: %s (%d)", |
|
| 190 |
+ prefix, strerror(-dco->status), dco->status); |
|
| 191 |
+ } |
|
| 192 |
+ |
|
| 193 |
+ return dco->status; |
|
| 194 |
+} |
|
| 195 |
+ |
|
| 196 |
+struct sockaddr * |
|
| 197 |
+mapped_v4_to_v6(struct sockaddr *sock, struct gc_arena *gc) |
|
| 198 |
+{
|
|
| 199 |
+ struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sock; |
|
| 200 |
+ if (sock->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sock6->sin6_addr)) |
|
| 201 |
+ {
|
|
| 202 |
+ |
|
| 203 |
+ struct sockaddr_in *sock4; |
|
| 204 |
+ ALLOC_OBJ_CLEAR_GC(sock4, struct sockaddr_in, gc); |
|
| 205 |
+ memcpy(&sock4->sin_addr, sock6->sin6_addr.s6_addr + 12, 4); |
|
| 206 |
+ sock4->sin_port = sock6->sin6_port; |
|
| 207 |
+ sock4->sin_family = AF_INET; |
|
| 208 |
+ return (struct sockaddr *)sock4; |
|
| 209 |
+ } |
|
| 210 |
+ return sock; |
|
| 211 |
+} |
|
| 212 |
+ |
|
| 213 |
+int |
|
| 214 |
+dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, |
|
| 215 |
+ struct sockaddr *localaddr, struct sockaddr *remoteaddr, |
|
| 216 |
+ struct in_addr *remote_in4, struct in6_addr *remote_in6) |
|
| 217 |
+{
|
|
| 218 |
+ msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd); |
|
| 219 |
+ |
|
| 220 |
+ struct gc_arena gc = gc_new(); |
|
| 221 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_NEW_PEER); |
|
| 222 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_NEW_PEER); |
|
| 223 |
+ int ret = -EMSGSIZE; |
|
| 224 |
+ |
|
| 225 |
+ NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_PEER_ID, peerid); |
|
| 226 |
+ NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_SOCKET, sd); |
|
| 227 |
+ |
|
| 228 |
+ /* Set the remote endpoint if defined (for UDP) */ |
|
| 229 |
+ if (remoteaddr) |
|
| 230 |
+ {
|
|
| 231 |
+ remoteaddr = mapped_v4_to_v6(remoteaddr, &gc); |
|
| 232 |
+ int alen = af_addr_size(remoteaddr->sa_family); |
|
| 233 |
+ |
|
| 234 |
+ NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_SOCKADDR_REMOTE, alen, remoteaddr); |
|
| 235 |
+ } |
|
| 236 |
+ |
|
| 237 |
+ if (localaddr) |
|
| 238 |
+ {
|
|
| 239 |
+ localaddr = mapped_v4_to_v6(localaddr, &gc); |
|
| 240 |
+ if (localaddr->sa_family == AF_INET) |
|
| 241 |
+ {
|
|
| 242 |
+ NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_LOCAL_IP, sizeof(struct in_addr), |
|
| 243 |
+ &((struct sockaddr_in *)localaddr)->sin_addr); |
|
| 244 |
+ } |
|
| 245 |
+ else if (localaddr->sa_family == AF_INET6) |
|
| 246 |
+ {
|
|
| 247 |
+ NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_LOCAL_IP, sizeof(struct in6_addr), |
|
| 248 |
+ &((struct sockaddr_in6 *)localaddr)->sin6_addr); |
|
| 249 |
+ } |
|
| 250 |
+ } |
|
| 251 |
+ |
|
| 252 |
+ /* Set the primary VPN IP addresses of the peer */ |
|
| 253 |
+ if (remote_in4) |
|
| 254 |
+ {
|
|
| 255 |
+ NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_IPV4, remote_in4->s_addr); |
|
| 256 |
+ } |
|
| 257 |
+ if (remote_in6) |
|
| 258 |
+ {
|
|
| 259 |
+ NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_IPV6, sizeof(struct in6_addr), |
|
| 260 |
+ remote_in6); |
|
| 261 |
+ } |
|
| 262 |
+ nla_nest_end(nl_msg, attr); |
|
| 263 |
+ |
|
| 264 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 265 |
+ |
|
| 266 |
+nla_put_failure: |
|
| 267 |
+ nlmsg_free(nl_msg); |
|
| 268 |
+ gc_free(&gc); |
|
| 269 |
+ return ret; |
|
| 270 |
+} |
|
| 271 |
+ |
|
| 272 |
+static int |
|
| 273 |
+ovpn_nl_cb_finish(struct nl_msg (*msg) __attribute__ ((unused)), void *arg) |
|
| 274 |
+{
|
|
| 275 |
+ int *status = arg; |
|
| 276 |
+ |
|
| 277 |
+ *status = 0; |
|
| 278 |
+ return NL_SKIP; |
|
| 279 |
+} |
|
| 280 |
+ |
|
| 281 |
+/* This function is used as error callback on the netlink socket. |
|
| 282 |
+ * When something goes wrong and the kernel returns an error, this function is |
|
| 283 |
+ * invoked. |
|
| 284 |
+ * |
|
| 285 |
+ * We pass the error code to the user by means of a variable pointed by *arg |
|
| 286 |
+ * (supplied by the user when setting this callback) and we parse the kernel |
|
| 287 |
+ * reply to see if it contains a human readable error. If found, it is printed. |
|
| 288 |
+ */ |
|
| 289 |
+static int |
|
| 290 |
+ovpn_nl_cb_error(struct sockaddr_nl (*nla) __attribute__ ((unused)), |
|
| 291 |
+ struct nlmsgerr *err, void *arg) |
|
| 292 |
+{
|
|
| 293 |
+ struct nlmsghdr *nlh = (struct nlmsghdr *)err - 1; |
|
| 294 |
+ struct nlattr *tb_msg[NLMSGERR_ATTR_MAX + 1]; |
|
| 295 |
+ int len = nlh->nlmsg_len; |
|
| 296 |
+ struct nlattr *attrs; |
|
| 297 |
+ int *ret = arg; |
|
| 298 |
+ int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); |
|
| 299 |
+ |
|
| 300 |
+ *ret = err->error; |
|
| 301 |
+ |
|
| 302 |
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) |
|
| 303 |
+ {
|
|
| 304 |
+ return NL_STOP; |
|
| 305 |
+ } |
|
| 306 |
+ |
|
| 307 |
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) |
|
| 308 |
+ {
|
|
| 309 |
+ ack_len += err->msg.nlmsg_len - sizeof(*nlh); |
|
| 310 |
+ } |
|
| 311 |
+ |
|
| 312 |
+ if (len <= ack_len) |
|
| 313 |
+ {
|
|
| 314 |
+ return NL_STOP; |
|
| 315 |
+ } |
|
| 316 |
+ |
|
| 317 |
+ attrs = (void *)((unsigned char *)nlh + ack_len); |
|
| 318 |
+ len -= ack_len; |
|
| 319 |
+ |
|
| 320 |
+ nla_parse(tb_msg, NLMSGERR_ATTR_MAX, attrs, len, NULL); |
|
| 321 |
+ if (tb_msg[NLMSGERR_ATTR_MSG]) |
|
| 322 |
+ {
|
|
| 323 |
+ len = strnlen((char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]), |
|
| 324 |
+ nla_len(tb_msg[NLMSGERR_ATTR_MSG])); |
|
| 325 |
+ msg(M_WARN, "kernel error: %*s\n", len, |
|
| 326 |
+ (char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG])); |
|
| 327 |
+ } |
|
| 328 |
+ |
|
| 329 |
+ return NL_STOP; |
|
| 330 |
+} |
|
| 331 |
+ |
|
| 332 |
+static void |
|
| 333 |
+ovpn_dco_init_netlink(dco_context_t *dco) |
|
| 334 |
+{
|
|
| 335 |
+ dco->ovpn_dco_id = resolve_ovpn_netlink_id(M_ERR); |
|
| 336 |
+ |
|
| 337 |
+ dco->nl_sock = nl_socket_alloc(); |
|
| 338 |
+ |
|
| 339 |
+ if (!dco->nl_sock) |
|
| 340 |
+ {
|
|
| 341 |
+ msg(M_ERR, "Cannot create netlink socket"); |
|
| 342 |
+ } |
|
| 343 |
+ |
|
| 344 |
+ /* TODO: Why are we setting this buffer size? */ |
|
| 345 |
+ nl_socket_set_buffer_size(dco->nl_sock, 8192, 8192); |
|
| 346 |
+ |
|
| 347 |
+ int ret = genl_connect(dco->nl_sock); |
|
| 348 |
+ if (ret) |
|
| 349 |
+ {
|
|
| 350 |
+ msg(M_ERR, "Cannot connect to generic netlink: %s", |
|
| 351 |
+ nl_geterror(ret)); |
|
| 352 |
+ } |
|
| 353 |
+ |
|
| 354 |
+ set_cloexec(nl_socket_get_fd(dco->nl_sock)); |
|
| 355 |
+ |
|
| 356 |
+ dco->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); |
|
| 357 |
+ if (!dco->nl_cb) |
|
| 358 |
+ {
|
|
| 359 |
+ msg(M_ERR, "failed to allocate netlink callback"); |
|
| 360 |
+ } |
|
| 361 |
+ |
|
| 362 |
+ nl_socket_set_cb(dco->nl_sock, dco->nl_cb); |
|
| 363 |
+ |
|
| 364 |
+ nl_cb_err(dco->nl_cb, NL_CB_CUSTOM, ovpn_nl_cb_error, &dco->status); |
|
| 365 |
+ nl_cb_set(dco->nl_cb, NL_CB_FINISH, NL_CB_CUSTOM, ovpn_nl_cb_finish, |
|
| 366 |
+ &dco->status); |
|
| 367 |
+ nl_cb_set(dco->nl_cb, NL_CB_ACK, NL_CB_CUSTOM, ovpn_nl_cb_finish, |
|
| 368 |
+ &dco->status); |
|
| 369 |
+ |
|
| 370 |
+ /* The async PACKET messages confuse libnl and it will drop them with |
|
| 371 |
+ * wrong sequence numbers (NLE_SEQ_MISMATCH), so disable libnl's sequence |
|
| 372 |
+ * number check */ |
|
| 373 |
+ nl_socket_disable_seq_check(dco->nl_sock); |
|
| 374 |
+} |
|
| 375 |
+ |
|
| 376 |
+bool |
|
| 377 |
+ovpn_dco_init(int mode, dco_context_t *dco) |
|
| 378 |
+{
|
|
| 379 |
+ switch (mode) |
|
| 380 |
+ {
|
|
| 381 |
+ case CM_TOP: |
|
| 382 |
+ dco->ifmode = OVPN_MODE_MP; |
|
| 383 |
+ break; |
|
| 384 |
+ |
|
| 385 |
+ case CM_P2P: |
|
| 386 |
+ dco->ifmode = OVPN_MODE_P2P; |
|
| 387 |
+ break; |
|
| 388 |
+ |
|
| 389 |
+ default: |
|
| 390 |
+ ASSERT(false); |
|
| 391 |
+ } |
|
| 392 |
+ |
|
| 393 |
+ ovpn_dco_init_netlink(dco); |
|
| 394 |
+ return true; |
|
| 395 |
+} |
|
| 396 |
+ |
|
| 397 |
+static void |
|
| 398 |
+ovpn_dco_uninit_netlink(dco_context_t *dco) |
|
| 399 |
+{
|
|
| 400 |
+ nl_socket_free(dco->nl_sock); |
|
| 401 |
+ dco->nl_sock = NULL; |
|
| 402 |
+ |
|
| 403 |
+ /* Decrease reference count */ |
|
| 404 |
+ nl_cb_put(dco->nl_cb); |
|
| 405 |
+ |
|
| 406 |
+ CLEAR(dco); |
|
| 407 |
+} |
|
| 408 |
+ |
|
| 409 |
+static void |
|
| 410 |
+ovpn_dco_register(dco_context_t *dco) |
|
| 411 |
+{
|
|
| 412 |
+ msg(D_DCO_DEBUG, __func__); |
|
| 413 |
+ ovpn_get_mcast_id(dco); |
|
| 414 |
+ |
|
| 415 |
+ if (dco->ovpn_dco_mcast_id < 0) |
|
| 416 |
+ {
|
|
| 417 |
+ msg(M_ERR, "cannot get mcast group: %s", nl_geterror(dco->ovpn_dco_mcast_id)); |
|
| 418 |
+ } |
|
| 419 |
+ |
|
| 420 |
+ /* Register for ovpn-dco specific multicast messages that the kernel may |
|
| 421 |
+ * send |
|
| 422 |
+ */ |
|
| 423 |
+ int ret = nl_socket_add_membership(dco->nl_sock, dco->ovpn_dco_mcast_id); |
|
| 424 |
+ if (ret) |
|
| 425 |
+ {
|
|
| 426 |
+ msg(M_ERR, "%s: failed to join groups: %d", __func__, ret); |
|
| 427 |
+ } |
|
| 428 |
+ |
|
| 429 |
+ /* Register for non-data packets that ovpn-dco may receive. They will be |
|
| 430 |
+ * forwarded to userspace |
|
| 431 |
+ */ |
|
| 432 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_REGISTER_PACKET); |
|
| 433 |
+ if (!nl_msg) |
|
| 434 |
+ {
|
|
| 435 |
+ msg(M_ERR, "%s: cannot allocate message to register for control packets", |
|
| 436 |
+ __func__); |
|
| 437 |
+ } |
|
| 438 |
+ |
|
| 439 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 440 |
+ if (ret) |
|
| 441 |
+ {
|
|
| 442 |
+ msg(M_ERR, "%s: failed to register for control packets: %d", __func__, |
|
| 443 |
+ ret); |
|
| 444 |
+ } |
|
| 445 |
+ nlmsg_free(nl_msg); |
|
| 446 |
+} |
|
| 447 |
+ |
|
| 448 |
+int |
|
| 449 |
+open_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx, const char *dev) |
|
| 450 |
+{
|
|
| 451 |
+ msg(D_DCO_DEBUG, "%s: %s", __func__, dev); |
|
| 452 |
+ ASSERT(tt->type == DEV_TYPE_TUN); |
|
| 453 |
+ |
|
| 454 |
+ int ret = net_iface_new(ctx, dev, "ovpn-dco", &tt->dco); |
|
| 455 |
+ if (ret < 0) |
|
| 456 |
+ {
|
|
| 457 |
+ msg(D_DCO_DEBUG, "Cannot create DCO interface %s: %d", dev, ret); |
|
| 458 |
+ return ret; |
|
| 459 |
+ } |
|
| 460 |
+ |
|
| 461 |
+ tt->dco.ifindex = if_nametoindex(dev); |
|
| 462 |
+ if (!tt->dco.ifindex) |
|
| 463 |
+ {
|
|
| 464 |
+ msg(M_FATAL, "DCO: cannot retrieve ifindex for interface %s", dev); |
|
| 465 |
+ } |
|
| 466 |
+ |
|
| 467 |
+ tt->actual_name = string_alloc(dev, NULL); |
|
| 468 |
+ uint8_t *dcobuf = malloc(65536); |
|
| 469 |
+ buf_set_write(&tt->dco.dco_packet_in, dcobuf, 65536); |
|
| 470 |
+ tt->dco.dco_message_peer_id = -1; |
|
| 471 |
+ |
|
| 472 |
+ ovpn_dco_register(&tt->dco); |
|
| 473 |
+ |
|
| 474 |
+ return 0; |
|
| 475 |
+} |
|
| 476 |
+ |
|
| 477 |
+void |
|
| 478 |
+close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx) |
|
| 479 |
+{
|
|
| 480 |
+ msg(D_DCO_DEBUG, __func__); |
|
| 481 |
+ |
|
| 482 |
+ net_iface_del(ctx, tt->actual_name); |
|
| 483 |
+ ovpn_dco_uninit_netlink(&tt->dco); |
|
| 484 |
+ free(tt->dco.dco_packet_in.data); |
|
| 485 |
+} |
|
| 486 |
+ |
|
| 487 |
+int |
|
| 488 |
+dco_swap_keys(dco_context_t *dco, unsigned int peerid) |
|
| 489 |
+{
|
|
| 490 |
+ msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid); |
|
| 491 |
+ |
|
| 492 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_SWAP_KEYS); |
|
| 493 |
+ if (!nl_msg) |
|
| 494 |
+ {
|
|
| 495 |
+ return -ENOMEM; |
|
| 496 |
+ } |
|
| 497 |
+ |
|
| 498 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_SWAP_KEYS); |
|
| 499 |
+ int ret = -EMSGSIZE; |
|
| 500 |
+ NLA_PUT_U32(nl_msg, OVPN_SWAP_KEYS_ATTR_PEER_ID, peerid); |
|
| 501 |
+ nla_nest_end(nl_msg, attr); |
|
| 502 |
+ |
|
| 503 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 504 |
+ |
|
| 505 |
+nla_put_failure: |
|
| 506 |
+ nlmsg_free(nl_msg); |
|
| 507 |
+ return ret; |
|
| 508 |
+} |
|
| 509 |
+ |
|
| 510 |
+ |
|
| 511 |
+int |
|
| 512 |
+dco_del_peer(dco_context_t *dco, unsigned int peerid) |
|
| 513 |
+{
|
|
| 514 |
+ msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid); |
|
| 515 |
+ |
|
| 516 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_DEL_PEER); |
|
| 517 |
+ if (!nl_msg) |
|
| 518 |
+ {
|
|
| 519 |
+ return -ENOMEM; |
|
| 520 |
+ } |
|
| 521 |
+ |
|
| 522 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_DEL_PEER); |
|
| 523 |
+ int ret = -EMSGSIZE; |
|
| 524 |
+ NLA_PUT_U32(nl_msg, OVPN_DEL_PEER_ATTR_PEER_ID, peerid); |
|
| 525 |
+ nla_nest_end(nl_msg, attr); |
|
| 526 |
+ |
|
| 527 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 528 |
+ |
|
| 529 |
+nla_put_failure: |
|
| 530 |
+ nlmsg_free(nl_msg); |
|
| 531 |
+ return ret; |
|
| 532 |
+} |
|
| 533 |
+ |
|
| 534 |
+ |
|
| 535 |
+int |
|
| 536 |
+dco_del_key(dco_context_t *dco, unsigned int peerid, |
|
| 537 |
+ dco_key_slot_t slot) |
|
| 538 |
+{
|
|
| 539 |
+ msg(D_DCO_DEBUG, "%s: peer-id %d, slot %d", __func__, peerid, slot); |
|
| 540 |
+ |
|
| 541 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_DEL_KEY); |
|
| 542 |
+ if (!nl_msg) |
|
| 543 |
+ {
|
|
| 544 |
+ return -ENOMEM; |
|
| 545 |
+ } |
|
| 546 |
+ |
|
| 547 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_DEL_KEY); |
|
| 548 |
+ int ret = -EMSGSIZE; |
|
| 549 |
+ NLA_PUT_U32(nl_msg, OVPN_DEL_KEY_ATTR_PEER_ID, peerid); |
|
| 550 |
+ NLA_PUT_U8(nl_msg, OVPN_DEL_KEY_ATTR_KEY_SLOT, slot); |
|
| 551 |
+ nla_nest_end(nl_msg, attr); |
|
| 552 |
+ |
|
| 553 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 554 |
+ |
|
| 555 |
+nla_put_failure: |
|
| 556 |
+ nlmsg_free(nl_msg); |
|
| 557 |
+ return ret; |
|
| 558 |
+} |
|
| 559 |
+ |
|
| 560 |
+int |
|
| 561 |
+dco_new_key(dco_context_t *dco, unsigned int peerid, int keyid, |
|
| 562 |
+ dco_key_slot_t slot, |
|
| 563 |
+ const uint8_t *encrypt_key, const uint8_t *encrypt_iv, |
|
| 564 |
+ const uint8_t *decrypt_key, const uint8_t *decrypt_iv, |
|
| 565 |
+ const char *ciphername) |
|
| 566 |
+{
|
|
| 567 |
+ msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s", |
|
| 568 |
+ __func__, slot, keyid, peerid, ciphername); |
|
| 569 |
+ |
|
| 570 |
+ const size_t key_len = cipher_kt_key_size(ciphername); |
|
| 571 |
+ const int nonce_tail_len = 8; |
|
| 572 |
+ |
|
| 573 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_NEW_KEY); |
|
| 574 |
+ if (!nl_msg) |
|
| 575 |
+ {
|
|
| 576 |
+ return -ENOMEM; |
|
| 577 |
+ } |
|
| 578 |
+ |
|
| 579 |
+ dco_cipher_t dco_cipher = dco_get_cipher(ciphername); |
|
| 580 |
+ |
|
| 581 |
+ int ret = -EMSGSIZE; |
|
| 582 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_NEW_KEY); |
|
| 583 |
+ NLA_PUT_U32(nl_msg, OVPN_NEW_KEY_ATTR_PEER_ID, peerid); |
|
| 584 |
+ NLA_PUT_U8(nl_msg, OVPN_NEW_KEY_ATTR_KEY_SLOT, slot); |
|
| 585 |
+ NLA_PUT_U8(nl_msg, OVPN_NEW_KEY_ATTR_KEY_ID, keyid); |
|
| 586 |
+ NLA_PUT_U16(nl_msg, OVPN_NEW_KEY_ATTR_CIPHER_ALG, dco_cipher); |
|
| 587 |
+ |
|
| 588 |
+ struct nlattr *key_enc = nla_nest_start(nl_msg, |
|
| 589 |
+ OVPN_NEW_KEY_ATTR_ENCRYPT_KEY); |
|
| 590 |
+ if (dco_cipher != OVPN_CIPHER_ALG_NONE) |
|
| 591 |
+ {
|
|
| 592 |
+ NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, key_len, encrypt_key); |
|
| 593 |
+ NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_NONCE_TAIL, nonce_tail_len, |
|
| 594 |
+ encrypt_iv); |
|
| 595 |
+ } |
|
| 596 |
+ nla_nest_end(nl_msg, key_enc); |
|
| 597 |
+ |
|
| 598 |
+ struct nlattr *key_dec = nla_nest_start(nl_msg, |
|
| 599 |
+ OVPN_NEW_KEY_ATTR_DECRYPT_KEY); |
|
| 600 |
+ if (dco_cipher != OVPN_CIPHER_ALG_NONE) |
|
| 601 |
+ {
|
|
| 602 |
+ NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, key_len, decrypt_key); |
|
| 603 |
+ NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_NONCE_TAIL, nonce_tail_len, |
|
| 604 |
+ decrypt_iv); |
|
| 605 |
+ } |
|
| 606 |
+ nla_nest_end(nl_msg, key_dec); |
|
| 607 |
+ |
|
| 608 |
+ nla_nest_end(nl_msg, attr); |
|
| 609 |
+ |
|
| 610 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 611 |
+ |
|
| 612 |
+nla_put_failure: |
|
| 613 |
+ nlmsg_free(nl_msg); |
|
| 614 |
+ return ret; |
|
| 615 |
+} |
|
| 616 |
+ |
|
| 617 |
+int |
|
| 618 |
+dco_set_peer(dco_context_t *dco, unsigned int peerid, |
|
| 619 |
+ int keepalive_interval, int keepalive_timeout, int mss) |
|
| 620 |
+{
|
|
| 621 |
+ msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d, mss %d", __func__, |
|
| 622 |
+ peerid, keepalive_interval, keepalive_timeout, mss); |
|
| 623 |
+ |
|
| 624 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_SET_PEER); |
|
| 625 |
+ if (!nl_msg) |
|
| 626 |
+ {
|
|
| 627 |
+ return -ENOMEM; |
|
| 628 |
+ } |
|
| 629 |
+ |
|
| 630 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_SET_PEER); |
|
| 631 |
+ int ret = -EMSGSIZE; |
|
| 632 |
+ NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_PEER_ID, peerid); |
|
| 633 |
+ NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_KEEPALIVE_INTERVAL, |
|
| 634 |
+ keepalive_interval); |
|
| 635 |
+ NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_KEEPALIVE_TIMEOUT, |
|
| 636 |
+ keepalive_timeout); |
|
| 637 |
+ nla_nest_end(nl_msg, attr); |
|
| 638 |
+ |
|
| 639 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 640 |
+ |
|
| 641 |
+nla_put_failure: |
|
| 642 |
+ nlmsg_free(nl_msg); |
|
| 643 |
+ return ret; |
|
| 644 |
+} |
|
| 645 |
+ |
|
| 646 |
+/* This function parses the reply provided by the kernel to the CTRL_CMD_GETFAMILY |
|
| 647 |
+ * message. We parse the reply and we retrieve the multicast group ID associated |
|
| 648 |
+ * with the "ovpn-dco" netlink family. |
|
| 649 |
+ * |
|
| 650 |
+ * The ID is later used to subscribe to the multicast group and be notified |
|
| 651 |
+ * about any multicast message sent by the ovpn-dco kernel module. |
|
| 652 |
+ */ |
|
| 653 |
+static int |
|
| 654 |
+mcast_family_handler(struct nl_msg *msg, void *arg) |
|
| 655 |
+{
|
|
| 656 |
+ dco_context_t *dco = arg; |
|
| 657 |
+ struct nlattr *tb[CTRL_ATTR_MAX + 1]; |
|
| 658 |
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); |
|
| 659 |
+ |
|
| 660 |
+ nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
|
| 661 |
+ genlmsg_attrlen(gnlh, 0), NULL); |
|
| 662 |
+ |
|
| 663 |
+ if (!tb[CTRL_ATTR_MCAST_GROUPS]) |
|
| 664 |
+ {
|
|
| 665 |
+ return NL_SKIP; |
|
| 666 |
+ } |
|
| 667 |
+ |
|
| 668 |
+ struct nlattr *mcgrp; |
|
| 669 |
+ int rem_mcgrp; |
|
| 670 |
+ nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) |
|
| 671 |
+ {
|
|
| 672 |
+ struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1]; |
|
| 673 |
+ |
|
| 674 |
+ nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, |
|
| 675 |
+ nla_data(mcgrp), nla_len(mcgrp), NULL); |
|
| 676 |
+ |
|
| 677 |
+ if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] |
|
| 678 |
+ || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]) |
|
| 679 |
+ {
|
|
| 680 |
+ continue; |
|
| 681 |
+ } |
|
| 682 |
+ |
|
| 683 |
+ if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]), |
|
| 684 |
+ OVPN_NL_MULTICAST_GROUP_PEERS, |
|
| 685 |
+ nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0) |
|
| 686 |
+ {
|
|
| 687 |
+ continue; |
|
| 688 |
+ } |
|
| 689 |
+ dco->ovpn_dco_mcast_id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]); |
|
| 690 |
+ break; |
|
| 691 |
+ } |
|
| 692 |
+ |
|
| 693 |
+ return NL_SKIP; |
|
| 694 |
+} |
|
| 695 |
+/** |
|
| 696 |
+ * Lookup the multicast id for OpenVPN. This method and its help method currently |
|
| 697 |
+ * hardcode the lookup to OVPN_NL_NAME and OVPN_NL_MULTICAST_GROUP_PEERS but |
|
| 698 |
+ * extended in the future if we need to lookup more than one mcast id. |
|
| 699 |
+ */ |
|
| 700 |
+static int |
|
| 701 |
+ovpn_get_mcast_id(dco_context_t *dco) |
|
| 702 |
+{
|
|
| 703 |
+ dco->ovpn_dco_mcast_id = -ENOENT; |
|
| 704 |
+ |
|
| 705 |
+ /* Even though 'nlctrl' is a constant, there seem to be no library |
|
| 706 |
+ * provided define for it */ |
|
| 707 |
+ int ctrlid = genl_ctrl_resolve(dco->nl_sock, "nlctrl"); |
|
| 708 |
+ |
|
| 709 |
+ struct nl_msg *nl_msg = nlmsg_alloc(); |
|
| 710 |
+ if (!nl_msg) |
|
| 711 |
+ {
|
|
| 712 |
+ return -ENOMEM; |
|
| 713 |
+ } |
|
| 714 |
+ |
|
| 715 |
+ genlmsg_put(nl_msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0); |
|
| 716 |
+ |
|
| 717 |
+ int ret = -EMSGSIZE; |
|
| 718 |
+ NLA_PUT_STRING(nl_msg, CTRL_ATTR_FAMILY_NAME, OVPN_NL_NAME); |
|
| 719 |
+ |
|
| 720 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, mcast_family_handler, __func__); |
|
| 721 |
+ |
|
| 722 |
+nla_put_failure: |
|
| 723 |
+ nlmsg_free(nl_msg); |
|
| 724 |
+ return ret; |
|
| 725 |
+} |
|
| 726 |
+ |
|
| 727 |
+/* This function parses any netlink message sent by ovpn-dco to userspace */ |
|
| 728 |
+static int |
|
| 729 |
+ovpn_handle_msg(struct nl_msg *msg, void *arg) |
|
| 730 |
+{
|
|
| 731 |
+ dco_context_t *dco = arg; |
|
| 732 |
+ |
|
| 733 |
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); |
|
| 734 |
+ struct nlattr *attrs[OVPN_ATTR_MAX + 1]; |
|
| 735 |
+ struct nlmsghdr *nlh = nlmsg_hdr(msg); |
|
| 736 |
+ |
|
| 737 |
+ if (!genlmsg_valid_hdr(nlh, 0)) |
|
| 738 |
+ {
|
|
| 739 |
+ msg(D_DCO, "ovpn-dco: invalid header"); |
|
| 740 |
+ return NL_SKIP; |
|
| 741 |
+ } |
|
| 742 |
+ |
|
| 743 |
+ if (nla_parse(attrs, OVPN_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
|
| 744 |
+ genlmsg_attrlen(gnlh, 0), NULL)) |
|
| 745 |
+ {
|
|
| 746 |
+ msg(D_DCO, "received bogus data from ovpn-dco"); |
|
| 747 |
+ return NL_SKIP; |
|
| 748 |
+ } |
|
| 749 |
+ |
|
| 750 |
+ /* we must know which interface this message is referring to in order to |
|
| 751 |
+ * avoid mixing messages for other instances |
|
| 752 |
+ */ |
|
| 753 |
+ if (!attrs[OVPN_ATTR_IFINDEX]) |
|
| 754 |
+ {
|
|
| 755 |
+ msg(D_DCO, "ovpn-dco: Received message without ifindex"); |
|
| 756 |
+ return NL_SKIP; |
|
| 757 |
+ } |
|
| 758 |
+ |
|
| 759 |
+ uint32_t ifindex = nla_get_u32(attrs[OVPN_ATTR_IFINDEX]); |
|
| 760 |
+ if (ifindex != dco->ifindex) |
|
| 761 |
+ {
|
|
| 762 |
+ msg(D_DCO, "ovpn-dco: received message type %d with mismatched ifindex %d\n", |
|
| 763 |
+ gnlh->cmd, ifindex); |
|
| 764 |
+ return NL_SKIP; |
|
| 765 |
+ } |
|
| 766 |
+ |
|
| 767 |
+ /* based on the message type, we parse the subobject contained in the |
|
| 768 |
+ * message, that stores the type-specific attributes. |
|
| 769 |
+ * |
|
| 770 |
+ * the "dco" object is then filled accordingly with the information |
|
| 771 |
+ * retrieved from the message, so that the rest of the OpenVPN code can |
|
| 772 |
+ * react as need be. |
|
| 773 |
+ */ |
|
| 774 |
+ switch (gnlh->cmd) |
|
| 775 |
+ {
|
|
| 776 |
+ case OVPN_CMD_DEL_PEER: |
|
| 777 |
+ {
|
|
| 778 |
+ if (!attrs[OVPN_ATTR_DEL_PEER]) |
|
| 779 |
+ {
|
|
| 780 |
+ msg(D_DCO, "ovpn-dco: no attributes in OVPN_DEL_PEER message"); |
|
| 781 |
+ return NL_SKIP; |
|
| 782 |
+ } |
|
| 783 |
+ |
|
| 784 |
+ struct nlattr *dp_attrs[OVPN_DEL_PEER_ATTR_MAX + 1]; |
|
| 785 |
+ if (nla_parse_nested(dp_attrs, OVPN_DEL_PEER_ATTR_MAX, |
|
| 786 |
+ attrs[OVPN_ATTR_DEL_PEER], NULL)) |
|
| 787 |
+ {
|
|
| 788 |
+ msg(D_DCO, "received bogus del peer packet data from ovpn-dco"); |
|
| 789 |
+ return NL_SKIP; |
|
| 790 |
+ } |
|
| 791 |
+ |
|
| 792 |
+ if (!dp_attrs[OVPN_DEL_PEER_ATTR_REASON]) |
|
| 793 |
+ {
|
|
| 794 |
+ msg(D_DCO, "ovpn-dco: no reason in DEL_PEER message"); |
|
| 795 |
+ return NL_SKIP; |
|
| 796 |
+ } |
|
| 797 |
+ if (!dp_attrs[OVPN_DEL_PEER_ATTR_PEER_ID]) |
|
| 798 |
+ {
|
|
| 799 |
+ msg(D_DCO, "ovpn-dco: no peer-id in DEL_PEER message"); |
|
| 800 |
+ return NL_SKIP; |
|
| 801 |
+ } |
|
| 802 |
+ int reason = nla_get_u8(dp_attrs[OVPN_DEL_PEER_ATTR_REASON]); |
|
| 803 |
+ unsigned int peerid = nla_get_u32(dp_attrs[OVPN_DEL_PEER_ATTR_PEER_ID]); |
|
| 804 |
+ |
|
| 805 |
+ msg(D_DCO_DEBUG, "ovpn-dco: received CMD_DEL_PEER, ifindex: %d, peer-id %d, reason: %d", |
|
| 806 |
+ ifindex, peerid, reason); |
|
| 807 |
+ dco->dco_message_peer_id = peerid; |
|
| 808 |
+ dco->dco_del_peer_reason = reason; |
|
| 809 |
+ dco->dco_message_type = OVPN_CMD_DEL_PEER; |
|
| 810 |
+ |
|
| 811 |
+ break; |
|
| 812 |
+ } |
|
| 813 |
+ |
|
| 814 |
+ case OVPN_CMD_PACKET: |
|
| 815 |
+ {
|
|
| 816 |
+ if (!attrs[OVPN_ATTR_PACKET]) |
|
| 817 |
+ {
|
|
| 818 |
+ msg(D_DCO, "ovpn-dco: no packet in OVPN_CMD_PACKET message"); |
|
| 819 |
+ return NL_SKIP; |
|
| 820 |
+ } |
|
| 821 |
+ struct nlattr *pkt_attrs[OVPN_PACKET_ATTR_MAX + 1]; |
|
| 822 |
+ |
|
| 823 |
+ if (nla_parse_nested(pkt_attrs, OVPN_PACKET_ATTR_MAX, |
|
| 824 |
+ attrs[OVPN_ATTR_PACKET], NULL)) |
|
| 825 |
+ {
|
|
| 826 |
+ msg(D_DCO, "received bogus cmd packet data from ovpn-dco"); |
|
| 827 |
+ return NL_SKIP; |
|
| 828 |
+ } |
|
| 829 |
+ if (!pkt_attrs[OVPN_PACKET_ATTR_PEER_ID]) |
|
| 830 |
+ {
|
|
| 831 |
+ msg(D_DCO, "ovpn-dco: Received OVPN_CMD_PACKET message without peer id"); |
|
| 832 |
+ return NL_SKIP; |
|
| 833 |
+ } |
|
| 834 |
+ if (!pkt_attrs[OVPN_PACKET_ATTR_PACKET]) |
|
| 835 |
+ {
|
|
| 836 |
+ msg(D_DCO, "ovpn-dco: Received OVPN_CMD_PACKET message without packet"); |
|
| 837 |
+ return NL_SKIP; |
|
| 838 |
+ } |
|
| 839 |
+ |
|
| 840 |
+ unsigned int peerid = nla_get_u32(pkt_attrs[OVPN_PACKET_ATTR_PEER_ID]); |
|
| 841 |
+ |
|
| 842 |
+ uint8_t *data = nla_data(pkt_attrs[OVPN_PACKET_ATTR_PACKET]); |
|
| 843 |
+ int len = nla_len(pkt_attrs[OVPN_PACKET_ATTR_PACKET]); |
|
| 844 |
+ |
|
| 845 |
+ msg(D_DCO_DEBUG, "ovpn-dco: received OVPN_PACKET_ATTR_PACKET, ifindex: %d peer-id: %d, len %d", |
|
| 846 |
+ ifindex, peerid, len); |
|
| 847 |
+ if (BLEN(&dco->dco_packet_in) > 0) |
|
| 848 |
+ {
|
|
| 849 |
+ msg(D_DCO, "DCO packet buffer still full?!"); |
|
| 850 |
+ return NL_SKIP; |
|
| 851 |
+ } |
|
| 852 |
+ buf_init(&dco->dco_packet_in, 0); |
|
| 853 |
+ buf_write(&dco->dco_packet_in, data, len); |
|
| 854 |
+ dco->dco_message_peer_id = peerid; |
|
| 855 |
+ dco->dco_message_type = OVPN_CMD_PACKET; |
|
| 856 |
+ break; |
|
| 857 |
+ } |
|
| 858 |
+ |
|
| 859 |
+ default: |
|
| 860 |
+ msg(D_DCO, "ovpn-dco: received unknown command: %d", gnlh->cmd); |
|
| 861 |
+ dco->dco_message_type = 0; |
|
| 862 |
+ return NL_SKIP; |
|
| 863 |
+ } |
|
| 864 |
+ |
|
| 865 |
+ return NL_OK; |
|
| 866 |
+} |
|
| 867 |
+ |
|
| 868 |
+int |
|
| 869 |
+dco_do_read(dco_context_t *dco) |
|
| 870 |
+{
|
|
| 871 |
+ msg(D_DCO_DEBUG, __func__); |
|
| 872 |
+ nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ovpn_handle_msg, dco); |
|
| 873 |
+ |
|
| 874 |
+ return ovpn_nl_recvmsgs(dco, __func__); |
|
| 875 |
+} |
|
| 876 |
+ |
|
| 877 |
+int |
|
| 878 |
+dco_do_write(dco_context_t *dco, int peer_id, struct buffer *buf) |
|
| 879 |
+{
|
|
| 880 |
+ packet_size_type len = BLEN(buf); |
|
| 881 |
+ dmsg(D_STREAM_DEBUG, "DCO: WRITE %d offset=%d", (int)len, buf->offset); |
|
| 882 |
+ |
|
| 883 |
+ msg(D_DCO_DEBUG, "%s: peer-id %d, len=%d", __func__, peer_id, len); |
|
| 884 |
+ |
|
| 885 |
+ struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_PACKET); |
|
| 886 |
+ |
|
| 887 |
+ if (!nl_msg) |
|
| 888 |
+ {
|
|
| 889 |
+ return -ENOMEM; |
|
| 890 |
+ } |
|
| 891 |
+ |
|
| 892 |
+ struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_PACKET); |
|
| 893 |
+ int ret = -EMSGSIZE; |
|
| 894 |
+ NLA_PUT_U32(nl_msg, OVPN_PACKET_ATTR_PEER_ID, peer_id); |
|
| 895 |
+ NLA_PUT(nl_msg, OVPN_PACKET_ATTR_PACKET, len, BSTR(buf)); |
|
| 896 |
+ nla_nest_end(nl_msg, attr); |
|
| 897 |
+ |
|
| 898 |
+ ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); |
|
| 899 |
+ if (ret) |
|
| 900 |
+ {
|
|
| 901 |
+ goto nla_put_failure; |
|
| 902 |
+ } |
|
| 903 |
+ |
|
| 904 |
+ /* return the length of the written data in case of success */ |
|
| 905 |
+ ret = len; |
|
| 906 |
+ |
|
| 907 |
+nla_put_failure: |
|
| 908 |
+ nlmsg_free(nl_msg); |
|
| 909 |
+ return ret; |
|
| 910 |
+} |
|
| 911 |
+ |
|
| 912 |
+bool |
|
| 913 |
+dco_available(int msglevel) |
|
| 914 |
+{
|
|
| 915 |
+ if (resolve_ovpn_netlink_id(msglevel) < 0) |
|
| 916 |
+ {
|
|
| 917 |
+ msg(msglevel, |
|
| 918 |
+ "Note: Kernel support for ovpn-dco missing, disabling data channel offload."); |
|
| 919 |
+ return false; |
|
| 920 |
+ } |
|
| 921 |
+ return true; |
|
| 922 |
+} |
|
| 923 |
+ |
|
| 924 |
+void |
|
| 925 |
+dco_event_set(dco_context_t *dco, struct event_set *es, void *arg) |
|
| 926 |
+{
|
|
| 927 |
+ if (dco && dco->nl_sock) |
|
| 928 |
+ {
|
|
| 929 |
+ event_ctl(es, nl_socket_get_fd(dco->nl_sock), EVENT_READ, arg); |
|
| 930 |
+ } |
|
| 931 |
+} |
|
| 932 |
+ |
|
| 933 |
+#endif /* defined(ENABLE_DCO) && defined(TARGET_LINUX) */ |
| 0 | 934 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,60 @@ |
| 0 |
+/* |
|
| 1 |
+ * Interface to linux dco networking code |
|
| 2 |
+ * |
|
| 3 |
+ * Copyright (C) 2020-2022 Antonio Quartulli <a@unstable.cc> |
|
| 4 |
+ * Copyright (C) 2020-2022 Arne Schwabe <arne@rfc2549.org> |
|
| 5 |
+ * Copyright (C) 2020-2022 OpenVPN Inc <sales@openvpn.net> |
|
| 6 |
+ * |
|
| 7 |
+ * This program is free software; you can redistribute it and/or modify |
|
| 8 |
+ * it under the terms of the GNU General Public License version 2 |
|
| 9 |
+ * as published by the Free Software Foundation. |
|
| 10 |
+ * |
|
| 11 |
+ * This program is distributed in the hope that it will be useful, |
|
| 12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
+ * GNU General Public License for more details. |
|
| 15 |
+ * |
|
| 16 |
+ * You should have received a copy of the GNU General Public License |
|
| 17 |
+ * along with this program (see the file COPYING included with this |
|
| 18 |
+ * distribution); if not, write to the Free Software Foundation, Inc., |
|
| 19 |
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 20 |
+ */ |
|
| 21 |
+#ifndef DCO_LINUX_H |
|
| 22 |
+#define DCO_LINUX_H |
|
| 23 |
+ |
|
| 24 |
+#if defined(ENABLE_DCO) && defined(TARGET_LINUX) |
|
| 25 |
+ |
|
| 26 |
+#include "event.h" |
|
| 27 |
+ |
|
| 28 |
+#include "ovpn_dco_linux.h" |
|
| 29 |
+ |
|
| 30 |
+#include <netlink/socket.h> |
|
| 31 |
+#include <netlink/netlink.h> |
|
| 32 |
+ |
|
| 33 |
+typedef enum ovpn_key_slot dco_key_slot_t; |
|
| 34 |
+typedef enum ovpn_cipher_alg dco_cipher_t; |
|
| 35 |
+ |
|
| 36 |
+#define DCO_SUPPORTED_CIPHERS "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305" |
|
| 37 |
+ |
|
| 38 |
+typedef struct |
|
| 39 |
+{
|
|
| 40 |
+ struct nl_sock *nl_sock; |
|
| 41 |
+ struct nl_cb *nl_cb; |
|
| 42 |
+ int status; |
|
| 43 |
+ |
|
| 44 |
+ enum ovpn_mode ifmode; |
|
| 45 |
+ |
|
| 46 |
+ int ovpn_dco_id; |
|
| 47 |
+ int ovpn_dco_mcast_id; |
|
| 48 |
+ |
|
| 49 |
+ unsigned int ifindex; |
|
| 50 |
+ |
|
| 51 |
+ struct buffer dco_packet_in; |
|
| 52 |
+ |
|
| 53 |
+ int dco_message_type; |
|
| 54 |
+ int dco_message_peer_id; |
|
| 55 |
+ int dco_del_peer_reason; |
|
| 56 |
+} dco_context_t; |
|
| 57 |
+ |
|
| 58 |
+#endif /* defined(ENABLE_DCO) && defined(TARGET_LINUX) */ |
|
| 59 |
+#endif /* ifndef DCO_LINUX_H */ |
| ... | ... |
@@ -91,6 +91,7 @@ |
| 91 | 91 |
#define D_OSBUF LOGLEV(3, 43, 0) /* show socket/tun/tap buffer sizes */ |
| 92 | 92 |
#define D_PS_PROXY LOGLEV(3, 44, 0) /* messages related to --port-share option */ |
| 93 | 93 |
#define D_IFCONFIG LOGLEV(3, 0, 0) /* show ifconfig info (don't mute) */ |
| 94 |
+#define D_DCO LOGLEV(3, 0, 0) /* show DCO related messages */ |
|
| 94 | 95 |
|
| 95 | 96 |
#define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */ |
| 96 | 97 |
#define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */ |
| ... | ... |
@@ -114,6 +115,7 @@ |
| 114 | 114 |
#define D_TAP_WIN_DEBUG LOGLEV(6, 69, M_DEBUG) /* show TAP-Windows driver debug info */ |
| 115 | 115 |
#define D_CLIENT_NAT LOGLEV(6, 69, M_DEBUG) /* show client NAT debug info */ |
| 116 | 116 |
#define D_XKEY LOGLEV(6, 69, M_DEBUG) /* show xkey-provider debug info */ |
| 117 |
+#define D_DCO_DEBUG LOGLEV(6, 69, M_DEBUG) /* show DCO related lowlevel debug messages */ |
|
| 117 | 118 |
|
| 118 | 119 |
#define D_SHOW_KEYS LOGLEV(7, 70, M_DEBUG) /* show data channel encryption keys */ |
| 119 | 120 |
#define D_SHOW_KEY_SOURCE LOGLEV(7, 70, M_DEBUG) /* show data channel key source entropy */ |
| ... | ... |
@@ -276,9 +276,10 @@ |
| 276 | 276 |
<ClCompile Include="crypto.c" /> |
| 277 | 277 |
<ClCompile Include="crypto_openssl.c" /> |
| 278 | 278 |
<ClCompile Include="cryptoapi.c" /> |
| 279 |
- <ClCompile Include="env_set.c" /> |
|
| 279 |
+ <ClCompile Include="dco_linux.c" /> |
|
| 280 | 280 |
<ClCompile Include="dhcp.c" /> |
| 281 | 281 |
<ClCompile Include="dns.c" /> |
| 282 |
+ <ClCompile Include="env_set.c" /> |
|
| 282 | 283 |
<ClCompile Include="error.c" /> |
| 283 | 284 |
<ClCompile Include="event.c" /> |
| 284 | 285 |
<ClCompile Include="fdmisc.c" /> |
| ... | ... |
@@ -362,6 +363,9 @@ |
| 362 | 362 |
<ClInclude Include="crypto_backend.h" /> |
| 363 | 363 |
<ClInclude Include="crypto_openssl.h" /> |
| 364 | 364 |
<ClInclude Include="cryptoapi.h" /> |
| 365 |
+ <ClInclude Include="dco.h" /> |
|
| 366 |
+ <ClInclude Include="dco_internal.h" /> |
|
| 367 |
+ <ClInclude Include="dco_linux.h" /> |
|
| 365 | 368 |
<ClInclude Include="dhcp.h" /> |
| 366 | 369 |
<ClInclude Include="dns.h" /> |
| 367 | 370 |
<ClInclude Include="env_set.h" /> |
| ... | ... |
@@ -396,6 +400,7 @@ |
| 396 | 396 |
<ClInclude Include="openvpn.h" /> |
| 397 | 397 |
<ClInclude Include="options.h" /> |
| 398 | 398 |
<ClInclude Include="otime.h" /> |
| 399 |
+ <ClInclude Include="ovpn_dco_linux.h" /> |
|
| 399 | 400 |
<ClInclude Include="packet_id.h" /> |
| 400 | 401 |
<ClInclude Include="perf.h" /> |
| 401 | 402 |
<ClInclude Include="ping.h" /> |
| ... | ... |
@@ -36,6 +36,9 @@ |
| 36 | 36 |
<ClCompile Include="cryptoapi.c"> |
| 37 | 37 |
<Filter>Source Files</Filter> |
| 38 | 38 |
</ClCompile> |
| 39 |
+ <ClCompile Include="dco_linux.c"> |
|
| 40 |
+ <Filter>Source Files</Filter> |
|
| 41 |
+ </ClCompile> |
|
| 39 | 42 |
<ClCompile Include="dhcp.c"> |
| 40 | 43 |
<Filter>Source Files</Filter> |
| 41 | 44 |
</ClCompile> |
| ... | ... |
@@ -299,6 +302,15 @@ |
| 299 | 299 |
<ClInclude Include="cryptoapi.h"> |
| 300 | 300 |
<Filter>Header Files</Filter> |
| 301 | 301 |
</ClInclude> |
| 302 |
+ <ClCompile Include="dco.h"> |
|
| 303 |
+ <Filter>Header Files</Filter> |
|
| 304 |
+ </ClInclude> |
|
| 305 |
+ <ClInclude Include="dco_internal.h"> |
|
| 306 |
+ <Filter>Header Files</Filter> |
|
| 307 |
+ </ClInclude> |
|
| 308 |
+ <ClInclude Include="dco_linux.h"> |
|
| 309 |
+ <Filter>Header Files</Filter> |
|
| 310 |
+ </ClInclude> |
|
| 302 | 311 |
<ClInclude Include="dhcp.h"> |
| 303 | 312 |
<Filter>Header Files</Filter> |
| 304 | 313 |
</ClInclude> |
| ... | ... |
@@ -398,6 +410,9 @@ |
| 398 | 398 |
<ClInclude Include="otime.h"> |
| 399 | 399 |
<Filter>Header Files</Filter> |
| 400 | 400 |
</ClInclude> |
| 401 |
+ <ClInclude Include="ovpn_dco_linux.h"> |
|
| 402 |
+ <Filter>Header Files</Filter> |
|
| 403 |
+ </ClInclude> |
|
| 401 | 404 |
<ClInclude Include="packet_id.h"> |
| 402 | 405 |
<Filter>Header Files</Filter> |
| 403 | 406 |
</ClInclude> |
| 404 | 407 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,265 @@ |
| 0 |
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ |
|
| 1 |
+/* |
|
| 2 |
+ * OpenVPN data channel accelerator |
|
| 3 |
+ * |
|
| 4 |
+ * Copyright (C) 2019-2021 OpenVPN, Inc. |
|
| 5 |
+ * |
|
| 6 |
+ * Author: James Yonan <james@openvpn.net> |
|
| 7 |
+ * Antonio Quartulli <antonio@openvpn.net> |
|
| 8 |
+ */ |
|
| 9 |
+ |
|
| 10 |
+#ifndef _UAPI_LINUX_OVPN_DCO_H_ |
|
| 11 |
+#define _UAPI_LINUX_OVPN_DCO_H_ |
|
| 12 |
+ |
|
| 13 |
+#define OVPN_NL_NAME "ovpn-dco" |
|
| 14 |
+ |
|
| 15 |
+#define OVPN_NL_MULTICAST_GROUP_PEERS "peers" |
|
| 16 |
+ |
|
| 17 |
+/** |
|
| 18 |
+ * enum ovpn_nl_commands - supported netlink commands |
|
| 19 |
+ */ |
|
| 20 |
+enum ovpn_nl_commands {
|
|
| 21 |
+ /** |
|
| 22 |
+ * @OVPN_CMD_UNSPEC: unspecified command to catch errors |
|
| 23 |
+ */ |
|
| 24 |
+ OVPN_CMD_UNSPEC = 0, |
|
| 25 |
+ |
|
| 26 |
+ /** |
|
| 27 |
+ * @OVPN_CMD_NEW_PEER: Configure peer with its crypto keys |
|
| 28 |
+ */ |
|
| 29 |
+ OVPN_CMD_NEW_PEER, |
|
| 30 |
+ |
|
| 31 |
+ /** |
|
| 32 |
+ * @OVPN_CMD_SET_PEER: Tweak parameters for an existing peer |
|
| 33 |
+ */ |
|
| 34 |
+ OVPN_CMD_SET_PEER, |
|
| 35 |
+ |
|
| 36 |
+ /** |
|
| 37 |
+ * @OVPN_CMD_DEL_PEER: Remove peer from internal table |
|
| 38 |
+ */ |
|
| 39 |
+ OVPN_CMD_DEL_PEER, |
|
| 40 |
+ |
|
| 41 |
+ OVPN_CMD_NEW_KEY, |
|
| 42 |
+ |
|
| 43 |
+ OVPN_CMD_SWAP_KEYS, |
|
| 44 |
+ |
|
| 45 |
+ OVPN_CMD_DEL_KEY, |
|
| 46 |
+ |
|
| 47 |
+ /** |
|
| 48 |
+ * @OVPN_CMD_REGISTER_PACKET: Register for specific packet types to be |
|
| 49 |
+ * forwarded to userspace |
|
| 50 |
+ */ |
|
| 51 |
+ OVPN_CMD_REGISTER_PACKET, |
|
| 52 |
+ |
|
| 53 |
+ /** |
|
| 54 |
+ * @OVPN_CMD_PACKET: Send a packet from userspace to kernelspace. Also |
|
| 55 |
+ * used to send to userspace packets for which a process had registered |
|
| 56 |
+ * with OVPN_CMD_REGISTER_PACKET |
|
| 57 |
+ */ |
|
| 58 |
+ OVPN_CMD_PACKET, |
|
| 59 |
+ |
|
| 60 |
+ /** |
|
| 61 |
+ * @OVPN_CMD_GET_PEER: Retrieve the status of a peer or all peers |
|
| 62 |
+ */ |
|
| 63 |
+ OVPN_CMD_GET_PEER, |
|
| 64 |
+}; |
|
| 65 |
+ |
|
| 66 |
+enum ovpn_cipher_alg {
|
|
| 67 |
+ /** |
|
| 68 |
+ * @OVPN_CIPHER_ALG_NONE: No encryption - reserved for debugging only |
|
| 69 |
+ */ |
|
| 70 |
+ OVPN_CIPHER_ALG_NONE = 0, |
|
| 71 |
+ /** |
|
| 72 |
+ * @OVPN_CIPHER_ALG_AES_GCM: AES-GCM AEAD cipher with any allowed key size |
|
| 73 |
+ */ |
|
| 74 |
+ OVPN_CIPHER_ALG_AES_GCM, |
|
| 75 |
+ /** |
|
| 76 |
+ * @OVPN_CIPHER_ALG_CHACHA20_POLY1305: ChaCha20Poly1305 AEAD cipher |
|
| 77 |
+ */ |
|
| 78 |
+ OVPN_CIPHER_ALG_CHACHA20_POLY1305, |
|
| 79 |
+}; |
|
| 80 |
+ |
|
| 81 |
+enum ovpn_del_peer_reason {
|
|
| 82 |
+ __OVPN_DEL_PEER_REASON_FIRST, |
|
| 83 |
+ OVPN_DEL_PEER_REASON_TEARDOWN = __OVPN_DEL_PEER_REASON_FIRST, |
|
| 84 |
+ OVPN_DEL_PEER_REASON_USERSPACE, |
|
| 85 |
+ OVPN_DEL_PEER_REASON_EXPIRED, |
|
| 86 |
+ OVPN_DEL_PEER_REASON_TRANSPORT_ERROR, |
|
| 87 |
+ __OVPN_DEL_PEER_REASON_AFTER_LAST |
|
| 88 |
+}; |
|
| 89 |
+ |
|
| 90 |
+enum ovpn_key_slot {
|
|
| 91 |
+ __OVPN_KEY_SLOT_FIRST, |
|
| 92 |
+ OVPN_KEY_SLOT_PRIMARY = __OVPN_KEY_SLOT_FIRST, |
|
| 93 |
+ OVPN_KEY_SLOT_SECONDARY, |
|
| 94 |
+ __OVPN_KEY_SLOT_AFTER_LAST, |
|
| 95 |
+}; |
|
| 96 |
+ |
|
| 97 |
+enum ovpn_netlink_attrs {
|
|
| 98 |
+ OVPN_ATTR_UNSPEC = 0, |
|
| 99 |
+ OVPN_ATTR_IFINDEX, |
|
| 100 |
+ OVPN_ATTR_NEW_PEER, |
|
| 101 |
+ OVPN_ATTR_SET_PEER, |
|
| 102 |
+ OVPN_ATTR_DEL_PEER, |
|
| 103 |
+ OVPN_ATTR_NEW_KEY, |
|
| 104 |
+ OVPN_ATTR_SWAP_KEYS, |
|
| 105 |
+ OVPN_ATTR_DEL_KEY, |
|
| 106 |
+ OVPN_ATTR_PACKET, |
|
| 107 |
+ OVPN_ATTR_GET_PEER, |
|
| 108 |
+ |
|
| 109 |
+ __OVPN_ATTR_AFTER_LAST, |
|
| 110 |
+ OVPN_ATTR_MAX = __OVPN_ATTR_AFTER_LAST - 1, |
|
| 111 |
+}; |
|
| 112 |
+ |
|
| 113 |
+enum ovpn_netlink_key_dir_attrs {
|
|
| 114 |
+ OVPN_KEY_DIR_ATTR_UNSPEC = 0, |
|
| 115 |
+ OVPN_KEY_DIR_ATTR_CIPHER_KEY, |
|
| 116 |
+ OVPN_KEY_DIR_ATTR_NONCE_TAIL, |
|
| 117 |
+ |
|
| 118 |
+ __OVPN_KEY_DIR_ATTR_AFTER_LAST, |
|
| 119 |
+ OVPN_KEY_DIR_ATTR_MAX = __OVPN_KEY_DIR_ATTR_AFTER_LAST - 1, |
|
| 120 |
+}; |
|
| 121 |
+ |
|
| 122 |
+enum ovpn_netlink_new_key_attrs {
|
|
| 123 |
+ OVPN_NEW_KEY_ATTR_UNSPEC = 0, |
|
| 124 |
+ OVPN_NEW_KEY_ATTR_PEER_ID, |
|
| 125 |
+ OVPN_NEW_KEY_ATTR_KEY_SLOT, |
|
| 126 |
+ OVPN_NEW_KEY_ATTR_KEY_ID, |
|
| 127 |
+ OVPN_NEW_KEY_ATTR_CIPHER_ALG, |
|
| 128 |
+ OVPN_NEW_KEY_ATTR_ENCRYPT_KEY, |
|
| 129 |
+ OVPN_NEW_KEY_ATTR_DECRYPT_KEY, |
|
| 130 |
+ |
|
| 131 |
+ __OVPN_NEW_KEY_ATTR_AFTER_LAST, |
|
| 132 |
+ OVPN_NEW_KEY_ATTR_MAX = __OVPN_NEW_KEY_ATTR_AFTER_LAST - 1, |
|
| 133 |
+}; |
|
| 134 |
+ |
|
| 135 |
+enum ovpn_netlink_del_key_attrs {
|
|
| 136 |
+ OVPN_DEL_KEY_ATTR_UNSPEC = 0, |
|
| 137 |
+ OVPN_DEL_KEY_ATTR_PEER_ID, |
|
| 138 |
+ OVPN_DEL_KEY_ATTR_KEY_SLOT, |
|
| 139 |
+ |
|
| 140 |
+ __OVPN_DEL_KEY_ATTR_AFTER_LAST, |
|
| 141 |
+ OVPN_DEL_KEY_ATTR_MAX = __OVPN_DEL_KEY_ATTR_AFTER_LAST - 1, |
|
| 142 |
+}; |
|
| 143 |
+ |
|
| 144 |
+enum ovpn_netlink_swap_keys_attrs {
|
|
| 145 |
+ OVPN_SWAP_KEYS_ATTR_UNSPEC = 0, |
|
| 146 |
+ OVPN_SWAP_KEYS_ATTR_PEER_ID, |
|
| 147 |
+ |
|
| 148 |
+ __OVPN_SWAP_KEYS_ATTR_AFTER_LAST, |
|
| 149 |
+ OVPN_SWAP_KEYS_ATTR_MAX = __OVPN_SWAP_KEYS_ATTR_AFTER_LAST - 1, |
|
| 150 |
+ |
|
| 151 |
+}; |
|
| 152 |
+ |
|
| 153 |
+enum ovpn_netlink_new_peer_attrs {
|
|
| 154 |
+ OVPN_NEW_PEER_ATTR_UNSPEC = 0, |
|
| 155 |
+ OVPN_NEW_PEER_ATTR_PEER_ID, |
|
| 156 |
+ OVPN_NEW_PEER_ATTR_SOCKADDR_REMOTE, |
|
| 157 |
+ OVPN_NEW_PEER_ATTR_SOCKET, |
|
| 158 |
+ OVPN_NEW_PEER_ATTR_IPV4, |
|
| 159 |
+ OVPN_NEW_PEER_ATTR_IPV6, |
|
| 160 |
+ OVPN_NEW_PEER_ATTR_LOCAL_IP, |
|
| 161 |
+ |
|
| 162 |
+ __OVPN_NEW_PEER_ATTR_AFTER_LAST, |
|
| 163 |
+ OVPN_NEW_PEER_ATTR_MAX = __OVPN_NEW_PEER_ATTR_AFTER_LAST - 1, |
|
| 164 |
+}; |
|
| 165 |
+ |
|
| 166 |
+enum ovpn_netlink_set_peer_attrs {
|
|
| 167 |
+ OVPN_SET_PEER_ATTR_UNSPEC = 0, |
|
| 168 |
+ OVPN_SET_PEER_ATTR_PEER_ID, |
|
| 169 |
+ OVPN_SET_PEER_ATTR_KEEPALIVE_INTERVAL, |
|
| 170 |
+ OVPN_SET_PEER_ATTR_KEEPALIVE_TIMEOUT, |
|
| 171 |
+ |
|
| 172 |
+ __OVPN_SET_PEER_ATTR_AFTER_LAST, |
|
| 173 |
+ OVPN_SET_PEER_ATTR_MAX = __OVPN_SET_PEER_ATTR_AFTER_LAST - 1, |
|
| 174 |
+}; |
|
| 175 |
+ |
|
| 176 |
+enum ovpn_netlink_del_peer_attrs {
|
|
| 177 |
+ OVPN_DEL_PEER_ATTR_UNSPEC = 0, |
|
| 178 |
+ OVPN_DEL_PEER_ATTR_REASON, |
|
| 179 |
+ OVPN_DEL_PEER_ATTR_PEER_ID, |
|
| 180 |
+ |
|
| 181 |
+ __OVPN_DEL_PEER_ATTR_AFTER_LAST, |
|
| 182 |
+ OVPN_DEL_PEER_ATTR_MAX = __OVPN_DEL_PEER_ATTR_AFTER_LAST - 1, |
|
| 183 |
+}; |
|
| 184 |
+ |
|
| 185 |
+enum ovpn_netlink_get_peer_attrs {
|
|
| 186 |
+ OVPN_GET_PEER_ATTR_UNSPEC = 0, |
|
| 187 |
+ OVPN_GET_PEER_ATTR_PEER_ID, |
|
| 188 |
+ |
|
| 189 |
+ __OVPN_GET_PEER_ATTR_AFTER_LAST, |
|
| 190 |
+ OVPN_GET_PEER_ATTR_MAX = __OVPN_GET_PEER_ATTR_AFTER_LAST - 1, |
|
| 191 |
+}; |
|
| 192 |
+ |
|
| 193 |
+enum ovpn_netlink_get_peer_response_attrs {
|
|
| 194 |
+ OVPN_GET_PEER_RESP_ATTR_UNSPEC = 0, |
|
| 195 |
+ OVPN_GET_PEER_RESP_ATTR_PEER_ID, |
|
| 196 |
+ OVPN_GET_PEER_RESP_ATTR_SOCKADDR_REMOTE, |
|
| 197 |
+ OVPN_GET_PEER_RESP_ATTR_IPV4, |
|
| 198 |
+ OVPN_GET_PEER_RESP_ATTR_IPV6, |
|
| 199 |
+ OVPN_GET_PEER_RESP_ATTR_LOCAL_IP, |
|
| 200 |
+ OVPN_GET_PEER_RESP_ATTR_LOCAL_PORT, |
|
| 201 |
+ OVPN_GET_PEER_RESP_ATTR_KEEPALIVE_INTERVAL, |
|
| 202 |
+ OVPN_GET_PEER_RESP_ATTR_KEEPALIVE_TIMEOUT, |
|
| 203 |
+ OVPN_GET_PEER_RESP_ATTR_RX_BYTES, |
|
| 204 |
+ OVPN_GET_PEER_RESP_ATTR_TX_BYTES, |
|
| 205 |
+ OVPN_GET_PEER_RESP_ATTR_RX_PACKETS, |
|
| 206 |
+ OVPN_GET_PEER_RESP_ATTR_TX_PACKETS, |
|
| 207 |
+ |
|
| 208 |
+ __OVPN_GET_PEER_RESP_ATTR_AFTER_LAST, |
|
| 209 |
+ OVPN_GET_PEER_RESP_ATTR_MAX = __OVPN_GET_PEER_RESP_ATTR_AFTER_LAST - 1, |
|
| 210 |
+}; |
|
| 211 |
+ |
|
| 212 |
+enum ovpn_netlink_peer_stats_attrs {
|
|
| 213 |
+ OVPN_PEER_STATS_ATTR_UNSPEC = 0, |
|
| 214 |
+ OVPN_PEER_STATS_BYTES, |
|
| 215 |
+ OVPN_PEER_STATS_PACKETS, |
|
| 216 |
+ |
|
| 217 |
+ __OVPN_PEER_STATS_ATTR_AFTER_LAST, |
|
| 218 |
+ OVPN_PEER_STATS_ATTR_MAX = __OVPN_PEER_STATS_ATTR_AFTER_LAST - 1, |
|
| 219 |
+}; |
|
| 220 |
+ |
|
| 221 |
+enum ovpn_netlink_peer_attrs {
|
|
| 222 |
+ OVPN_PEER_ATTR_UNSPEC = 0, |
|
| 223 |
+ OVPN_PEER_ATTR_PEER_ID, |
|
| 224 |
+ OVPN_PEER_ATTR_SOCKADDR_REMOTE, |
|
| 225 |
+ OVPN_PEER_ATTR_IPV4, |
|
| 226 |
+ OVPN_PEER_ATTR_IPV6, |
|
| 227 |
+ OVPN_PEER_ATTR_LOCAL_IP, |
|
| 228 |
+ OVPN_PEER_ATTR_KEEPALIVE_INTERVAL, |
|
| 229 |
+ OVPN_PEER_ATTR_KEEPALIVE_TIMEOUT, |
|
| 230 |
+ OVPN_PEER_ATTR_ENCRYPT_KEY, |
|
| 231 |
+ OVPN_PEER_ATTR_DECRYPT_KEY, |
|
| 232 |
+ OVPN_PEER_ATTR_RX_STATS, |
|
| 233 |
+ OVPN_PEER_ATTR_TX_STATS, |
|
| 234 |
+ |
|
| 235 |
+ __OVPN_PEER_ATTR_AFTER_LAST, |
|
| 236 |
+ OVPN_PEER_ATTR_MAX = __OVPN_PEER_ATTR_AFTER_LAST - 1, |
|
| 237 |
+}; |
|
| 238 |
+ |
|
| 239 |
+enum ovpn_netlink_packet_attrs {
|
|
| 240 |
+ OVPN_PACKET_ATTR_UNSPEC = 0, |
|
| 241 |
+ OVPN_PACKET_ATTR_PACKET, |
|
| 242 |
+ OVPN_PACKET_ATTR_PEER_ID, |
|
| 243 |
+ |
|
| 244 |
+ __OVPN_PACKET_ATTR_AFTER_LAST, |
|
| 245 |
+ OVPN_PACKET_ATTR_MAX = __OVPN_PACKET_ATTR_AFTER_LAST - 1, |
|
| 246 |
+}; |
|
| 247 |
+ |
|
| 248 |
+enum ovpn_ifla_attrs {
|
|
| 249 |
+ IFLA_OVPN_UNSPEC = 0, |
|
| 250 |
+ IFLA_OVPN_MODE, |
|
| 251 |
+ |
|
| 252 |
+ __IFLA_OVPN_AFTER_LAST, |
|
| 253 |
+ IFLA_OVPN_MAX = __IFLA_OVPN_AFTER_LAST - 1, |
|
| 254 |
+}; |
|
| 255 |
+ |
|
| 256 |
+enum ovpn_mode {
|
|
| 257 |
+ __OVPN_MODE_FIRST = 0, |
|
| 258 |
+ OVPN_MODE_P2P = __OVPN_MODE_FIRST, |
|
| 259 |
+ OVPN_MODE_MP, |
|
| 260 |
+ |
|
| 261 |
+ __OVPN_MODE_AFTER_LAST, |
|
| 262 |
+}; |
|
| 263 |
+ |
|
| 264 |
+#endif /* _UAPI_LINUX_OVPN_DCO_H_ */ |
| ... | ... |
@@ -40,6 +40,7 @@ |
| 40 | 40 |
#include "misc.h" |
| 41 | 41 |
#include "networking.h" |
| 42 | 42 |
#include "ring_buffer.h" |
| 43 |
+#include "dco.h" |
|
| 43 | 44 |
|
| 44 | 45 |
#ifdef _WIN32 |
| 45 | 46 |
#define WINTUN_COMPONENT_ID "wintun" |
| ... | ... |
@@ -214,6 +215,8 @@ struct tuntap |
| 214 | 214 |
#endif |
| 215 | 215 |
/* used for printing status info only */ |
| 216 | 216 |
unsigned int rwflags_debug; |
| 217 |
+ |
|
| 218 |
+ dco_context_t dco; |
|
| 217 | 219 |
}; |
| 218 | 220 |
|
| 219 | 221 |
static inline bool |